00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
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>
00020
00021 #if defined(unix) || defined(__unix) || defined(__unix__)
00022 # include <unistd.h>
00023 # include <netdb.h>
00024 # include <sys/socket.h>
00025 # include <netinet/in.h>
00026 # ifdef __alpha
00027 # include <fp.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)
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;
00121
00122 char const *p = url+7;
00123 while (*p && *p!='/')
00124 ++p;
00125
00126
00127 vcl_string host = vcl_string(url+7, p);
00128 vcl_string path = (*p) ? p+1 : "";
00129 vcl_string auth;
00130 int port = 80;
00131
00132
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
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
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
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 WSAStartup( wVersionRequested, &wsaData );
00173 }
00174 #endif
00175
00176
00177 SOCKET tcp_socket = socket(PF_INET,
00178 SOCK_STREAM,
00179 PF_UNSPEC);
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
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
00211 sockaddr_in my_addr;
00212 my_addr.sin_family = AF_INET;
00213 my_addr.sin_port = htons(port);
00214 vcl_memcpy(&my_addr.sin_addr, hp->h_addr_list[0], hp->h_length);
00215
00216
00217 if (connect(tcp_socket , (sockaddr *) &my_addr, sizeof my_addr) < 0) {
00218 vcl_cerr << __FILE__ ": failed to connect to host\n";
00219
00220 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00221 closesocket(tcp_socket);
00222 #else
00223 close(tcp_socket);
00224 #endif
00225 return;
00226 }
00227
00228
00229 char buffer[4096];
00230
00231
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
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
00254 #if 1
00255 shutdown(tcp_socket, 1);
00256 #else
00257 for (int i=0; i<4096; ++i) ::write(tcp_socket, "\n\n\n\n", 4);
00258 #endif
00259
00260
00261
00262
00263 u_ = new vil1_stream_core;
00264 u_->ref();
00265 {
00266 unsigned entity_marker = 0;
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
00275
00276 assert (entity_marker < 5);
00277 if (entity_marker==4)
00278 {
00279 u_->write(buffer, n);
00280
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
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
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 }