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