core/vil1/vil1_stream_url.cxx

Go to the documentation of this file.
00001 // This is core/vil1/vil1_stream_url.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author fsm
00008 
00009 #include "vil1_stream_url.h"
00010 
00011 #include <vcl_cassert.h>
00012 #include <vcl_cstring.h>
00013 #include <vcl_cstdlib.h>
00014 #include <vcl_string.h>
00015 #include <vcl_iostream.h>
00016 #include <vil1/vil1_stream_core.h>
00017 #include <vcl_fstream.h>
00018 #undef sprintf // This works around a bug in libintl.h
00019 #include <vcl_cstdio.h>  // sprintf()
00020 
00021 #if defined(unix) || defined(__unix)
00022 # include <unistd.h>       // read(), write(), close()
00023 # include <netdb.h>        // gethostbyname(), sockaddr_in()
00024 # include <sys/socket.h>
00025 # include <netinet/in.h>   // htons()
00026 # ifdef __alpha
00027 #  include <fp.h>           // htons() [ on e.g. DEC alpha, htons is in machine/endian.h]
00028 # endif
00029 # define SOCKET int
00030 #elif defined (VCL_WIN32) && !defined(__CYGWIN__)
00031 # include <winsock2.h>
00032 #endif
00033 
00034 
00035 static const
00036 int base64_encoding[]=
00037 {
00038   'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
00039   'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
00040   'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
00041   'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
00042 };
00043 
00044 static char out_buf[4];
00045 
00046 static const char * encode_triplet(char data[3], unsigned n)
00047 {
00048   assert (n>0 && n <4);
00049   out_buf[0] = base64_encoding[(data[0] & 0xFC) >> 2];
00050 
00051   if (n==1)
00052   {
00053     out_buf[2] = out_buf[3] = '=';
00054     return out_buf;
00055   }
00056 
00057   out_buf[1] = base64_encoding[
00058     ((data[0] & 0x3) << 4) + ((data[1] & 0xf0)>>4)];
00059   out_buf[2] = base64_encoding[
00060     ((data[1] & 0xf) << 2) + ((data[2] & 0xc0)>>6)];
00061 
00062   if (n==2)
00063   {
00064     out_buf[3] = '=';
00065     return out_buf;
00066   }
00067 
00068   out_buf[3] = base64_encoding[ (data[2] & 0x3f) ];
00069   return out_buf;
00070 }
00071 
00072 //=======================================================================
00073 
00074 static vcl_string encode_base64(const vcl_string& in)
00075 {
00076   vcl_string out;
00077     unsigned i = 0, line_octets = 0;
00078   const unsigned l = in.size();
00079   char data[3];
00080     while (i < l)
00081     {
00082     data[0] = in[i++];
00083     data[1] = data[2] = 0;
00084 
00085     if (i == l)
00086     {
00087       out.append(encode_triplet(data,1),4);
00088       return out;
00089     }
00090 
00091     data[1] = in[i++];
00092 
00093     if (i == l)
00094     {
00095       out.append(encode_triplet(data,2),4);
00096       return out;
00097     }
00098 
00099     data[2] = in[i++];
00100 
00101     out.append(encode_triplet(data,3),4);
00102 
00103     if (line_octets >= 68/4) // print carriage return
00104     {
00105       out.append("\r\n",2);
00106       line_octets = 0;
00107     }
00108     else
00109       ++line_octets;
00110     }
00111 
00112     return out;
00113 }
00114 
00115 
00116 vil1_stream_url::vil1_stream_url(char const *url)
00117   : u_(0)
00118 {
00119   if (vcl_strncmp(url, "http://", 7) != 0)
00120     return; // doesn't look like a URL to me....
00121 
00122   char const *p = url+7;
00123   while (*p && *p!='/')
00124     ++p;
00125 
00126   // split URL into auth, host, path and port number.
00127   vcl_string host = vcl_string(url+7, p);
00128   vcl_string path = (*p) ? p+1 : "";
00129   vcl_string auth;
00130   int port = 80; // default
00131 
00132   //authentication
00133   for (unsigned int i=0; i<host.size(); ++i)
00134     if (host[i] == '@') {
00135       auth = vcl_string(host.c_str(), host.c_str()+i);
00136       host = vcl_string(host.c_str()+i+1, host.c_str() + host.size());
00137       break;
00138     }
00139 
00140   // port?
00141   for (unsigned int i=host.size()-1; i>0; --i)
00142     if (host[i] == ':') {
00143       port = vcl_atoi(host.c_str() + i + 1);
00144       host = vcl_string(host.c_str(), host.c_str() + i);
00145       break;
00146     }
00147 
00148   // do character translation
00149   for (unsigned k =0; k < path.size(); ++k)
00150     if (path[k] == ' ')
00151       path.replace(k, 1, "%20");
00152     else if (path[k] == '%')
00153       path.replace(k, 1, "%25");
00154 
00155   // so far so good.
00156 #ifdef DEBUG
00157   vcl_cerr << "auth = \'" << auth << "\'\n"
00158            << "host = \'" << host << "\'\n"
00159            << "path = \'" << path << "\'\n"
00160            << "port = " << port << vcl_endl;
00161 #endif
00162 
00163 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00164   static int called_WSAStartup;
00165   if (called_WSAStartup==0)
00166   {
00167     WORD wVersionRequested;
00168     WSADATA wsaData;
00169 
00170     wVersionRequested = MAKEWORD( 2, 2 );
00171 
00172     /* int err = */ WSAStartup( wVersionRequested, &wsaData );
00173   }
00174 #endif
00175 
00176   // create socket endpoint.
00177   SOCKET tcp_socket = socket(PF_INET,      // IPv4 protocols.
00178                              SOCK_STREAM,  // two-way, reliable, connection-based stream socket.
00179                              PF_UNSPEC);   // protocol number.
00180 
00181 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00182   if (tcp_socket == INVALID_SOCKET) {
00183     vcl_cerr << __FILE__ ": failed to create socket.\n";
00184 # ifndef NDEBUG
00185     vcl_cerr << "error code : " << WSAGetLastError() << vcl_endl;
00186 # endif
00187     return;
00188   }
00189 #else
00190   if (tcp_socket < 0)
00191     vcl_cerr << __FILE__ ": failed to create socket.\n";
00192 #endif
00193 
00194 #ifdef DEBUG
00195   vcl_cerr << __FILE__ ": tcp_sockect = " << tcp_socket << vcl_endl;
00196 #endif
00197 
00198   // get network address of server.
00199   hostent *hp = gethostbyname(host.c_str());
00200   if (! hp) {
00201     vcl_cerr << __FILE__ ": failed to lookup host\n";
00202 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00203     closesocket(tcp_socket);
00204 #else
00205     close(tcp_socket);
00206 #endif
00207     return;
00208   }
00209 
00210   // make socket address.
00211   sockaddr_in my_addr;
00212   my_addr.sin_family = AF_INET;
00213   my_addr.sin_port = htons(port);  // convert port number to network byte order..
00214   vcl_memcpy(&my_addr.sin_addr, hp->h_addr_list[0], hp->h_length);
00215 
00216   // connect to server.
00217   if (connect(tcp_socket , (sockaddr *) &my_addr, sizeof my_addr) < 0) {
00218     vcl_cerr << __FILE__ ": failed to connect to host\n";
00219     //perror(__FILE__);
00220 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00221     closesocket(tcp_socket);
00222 #else
00223     close(tcp_socket);
00224 #endif
00225     return;
00226   }
00227 
00228   // buffer for data transfers over socket.
00229   char buffer[4096];
00230 
00231   // send HTTP 1.1 request.
00232   vcl_sprintf(buffer, "GET /%s / HTTP/1.1\n", path.c_str());
00233   if (auth != "")
00234     vcl_sprintf(buffer+vcl_strlen(buffer), "Authorization:  Basic %s\n", encode_base64(auth).c_str());
00235 //    vcl_sprintf(buffer+vcl_strlen(buffer), "Authorization:  user  testuser:testuser\n");
00236 
00237 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00238   if (send(tcp_socket, buffer, vcl_strlen(buffer), 0) < 0)
00239   {
00240     vcl_cerr << __FILE__ ": error sending HTTP request\n";
00241     closesocket(tcp_socket);
00242     return;
00243   }
00244 #else
00245   if (::write(tcp_socket, buffer, vcl_strlen(buffer)) < 0)
00246   {
00247     vcl_cerr << __FILE__ ": error sending HTTP request\n";
00248     close(tcp_socket);
00249     return;
00250   }
00251 #endif
00252 
00253   // force the data to be sent.
00254 #if 1
00255   shutdown(tcp_socket, 1); // disallow further sends.
00256 #else
00257   for (int i=0; i<4096; ++i) ::write(tcp_socket, "\n\n\n\n", 4);
00258 #endif
00259 
00260 //  vcl_ofstream test2("/test2.jpg", vcl_ios_binary);
00261 
00262   // read from socket into memory.
00263   u_ = new vil1_stream_core;
00264   u_->ref();
00265   {
00266     unsigned entity_marker = 0; // count end of header CR and LFs
00267     vil1_streampos n;
00268 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00269     while ((n = recv(tcp_socket, buffer, sizeof buffer,0 )) > 0L)
00270 #else
00271     while ((n = ::read(tcp_socket, buffer, sizeof buffer)) > 0L)
00272 #endif
00273     {
00274       // search for the CRLFCRLF sequence that marks the end
00275       // of the http response header
00276       assert (entity_marker < 5);
00277       if (entity_marker==4)
00278       {
00279         u_->write(buffer, n);
00280 //        test2.write(buffer, n);
00281       }
00282       else
00283       {
00284         for (vil1_streampos i=0; i<n; ++i)
00285         {
00286           if ((entity_marker==2||entity_marker==0) && buffer[i]=='\r') entity_marker++;
00287           else if (entity_marker==1 && buffer[i]=='\n') entity_marker++;
00288           else if (entity_marker==3 && buffer[i]=='\n')
00289           {
00290             entity_marker++;
00291             u_->write(buffer+i+1, n-i-1);
00292 //            test2.write(buffer+i+1, n-i-1);
00293             break;
00294           }
00295           else entity_marker=0;
00296         }
00297       }
00298     }
00299   }
00300 
00301 #if 0 // useful for figuring out where the error is
00302   char btest[4096];
00303   vcl_ofstream test("/test.jpg", vcl_ios_binary);
00304   u_->seek(0L);
00305   while (vil1_streampos bn = u_->read(btest, 4096L))
00306     test.write(btest, bn);
00307   test.close();
00308 #endif
00309 
00310 
00311   // close connection to server.
00312 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00313   closesocket(tcp_socket);
00314 #else
00315   close(tcp_socket);
00316 #endif
00317 }
00318 
00319 vil1_stream_url::~vil1_stream_url()
00320 {
00321   if (u_) {
00322     u_->unref();
00323     u_ = 0;
00324   }
00325 }

Generated on Sat Nov 22 05:08:29 2008 for core/vil1 by  doxygen 1.5.1