ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/proj/trunk/Search/HttpHandler.cpp
(Generate patch)

Comparing trunk/Search/HttpHandler.cpp (file contents):
Revision 1 by douglas, 2002-12-04T20:22:59-08:00 vs.
Revision 145 by douglas, 2003-05-31T14:31:50-07:00

# Line 1 | Line 1
1   /* ============================================================================
2   * Douglas Thrift's Search Engine License
3   *
4 < * Copyright (C) 2002, Douglas Thrift. All Rights Reserved.
4 > * Copyright (C) 2002-2003, Douglas Thrift. All Rights Reserved.
5   * Redistribution and use in source and binary forms, with or without
6   * modification, are permitted provided that the following conditions are met:
7   *
# Line 50 | Line 50
50  
51   #include "HttpHandler.h"
52  
53 #ifdef _WIN32
54 #define PATH_SEPARATOR "\\"
55 #define ENV_SEPARATOR ';'
56 #else
57 #define PATH_SEPARATOR "/"
58 #define ENV_SEPARATOR ':'
59 #endif
60
53   HttpHandler::HttpHandler()
54   {
55 <        string arguments = "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/Strin"
64 <                + string("g;Ljava/lang/String;)Ljava/lang/String;");
55 >        buffer = new char[BUFSIZ + 1];
56  
57 <        begin = 0;
58 <
59 <        setJarPath();
57 > #ifdef _WIN32
58 >        if (WSAStartup(MAKEWORD(2, 0), &data) != 0)
59 >        {
60 >                error(program + ": WSAStartup");
61 >                exit(1);
62 >        }
63 > #endif // _WIN32
64  
65 < //      options[0].optionString = jarPath;
66 < //      memset(&vm_args, 0, sizeof (vm_args));
72 < //      vm_args.version = JNI_VERSION_1_4;
73 < //      vm_args.nOptions = 1;
74 < //      vm_args.options = options;
75 <
76 < //      status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
77 <
78 < //      if (status != JNI_ERR)
79 < //      {
80 < //              cls = env->FindClass("HttpConnector");
81 <
82 < //              if (cls != 0)
83 < //              {
84 < //                      mid = env->GetStaticMethodID(cls, "connect", arguments.c_str());
85 < //              }
86 < //      }
65 >        length = 0;
66 >        chunked = false;
67   }
68  
69   HttpHandler::~HttpHandler()
70   {
71 < //      if (status != JNI_ERR)
92 < //      {
93 < //              jvm->DestroyJavaVM();
94 < //      }
71 >        delete [] buffer;
72  
73 < //      delete [] jarPath;
73 > #ifdef _WIN32
74 >        WSACleanup();
75 > #endif // _WIN32
76   }
77  
78 < bool HttpHandler::connect(URL& url)
78 > bool HttpHandler::handle(URL &url, const string referer, bool head)
79   {
80          bool answer = false;
81  
82 < //      if (status != JNI_ERR)
83 < //      {
84 < //              if (cls != 0)
85 < //              {
86 < //                      if (mid != 0)
108 < //                      {
109 < //                              jstring addressJ = env->NewStringUTF(url.getAddress().c_str());
110 < //                              jint portJ = url.getPort();
111 < //                              jstring pathJ = env->NewStringUTF(url.getPath().c_str());
112 < //                              jstring programNameJ = env->NewStringUTF(programName.c_str());
113 < //                              jstring programVersionJ =
114 < //                                      env->NewStringUTF(programVersion.c_str());
115 <
116 < //                              jstring pageJ = (jstring)env->CallStaticObjectMethod(cls, mid,
117 < //                                      addressJ, portJ, pathJ, programNameJ, programVersionJ);
118 <
119 < //                              const char* pageC = env->GetStringUTFChars(pageJ, 0);
120 < //                              page = pageC;
121 < //                              env->ReleaseStringUTFChars(pageJ, pageC);
122 <
123 < //                              if (page != "unknown host\n" && page != "io exception\n" &&
124 < //                                      page != "bad headers\n") answer = true;
125 < //                      }
126 < //              }
127 < //      }
82 >        if ((http = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
83 >        {
84 >                error(program + ": Socket");
85 >                exit(1);
86 >        }
87  
88 <        return answer;
89 < }
88 >        sockaddr_in address;
89 >        hostent* host;
90  
91 < HttpHandler& HttpHandler::getline(string& line, char endline)
133 < {
134 <        int end = page.find(endline, begin);
135 <        int newline = page.find('\n', begin);
91 >        address.sin_family = AF_INET;
92  
93 <        if (newline < end || end == string::npos)
93 >        if ((host = gethostbyname(url.getAddress().c_str())) == NULL)
94          {
95 <                end = newline;
95 >                error(program + ": Host: " + url.getAddress(), true);
96 >                return answer;
97          }
98  
99 <        line = page.substr(begin, end - begin);
99 >        address.sin_addr = *((in_addr*)*host->h_addr_list);
100 >        address.sin_port = htons(url.getPort());
101  
102 <        if (end == string::npos)
102 >        if (connect(http, (sockaddr*)&address, sizeof(sockaddr_in)) ==
103 >                SOCKET_ERROR)
104          {
105 <                begin = end;
105 >                error(program + ": Connect");
106 >                return answer;
107 >        }
108 >
109 >        if (head)
110 >        {
111 >                putline("HEAD " + url.getPath() + " HTTP/1.1");
112          }
113          else
114          {
115 <                begin = end + 1;
115 >                putline("GET " + url.getPath() + " HTTP/1.1");
116          }
117  
118 <        return *this;
119 < }
118 >        putline("Accept: text/html; text/plain");
119 >        putline("User-Agent: " + agent(true) + ' ' + platform());
120  
121 < bool HttpHandler::good()
122 < {
123 <        bool answer = true;
121 >        if (url.getPort() == 80)
122 >        {
123 >                putline("Host: " + url.getAddress());
124 >        }
125 >        else
126 >        {
127 >                char* port = new char[1024];
128 >                sprintf(port, "%u", url.getPort());
129 >
130 >                putline("Host: " + url.getAddress() + ':' + port);
131  
132 <        if (begin >= page.length())
132 >                delete [] port;
133 >        }
134 >
135 >        if (referer != "")
136          {
137 <                answer = false;
137 >                putline("Referer: " + referer);
138          }
139 <        else if (begin == string::npos)
139 >
140 >        putline("Connection: close");
141 >        putline();
142 >
143 >        code response;
144 >        string line;
145 >
146 >        do
147          {
148 <                answer = false;
148 >                line = getline();
149 >
150 >                if (line.find("HTTP/") != 0)
151 >                {
152 >                        return answer;
153 >                }
154 >
155 >                unsigned dot = line.find('.');
156 >                unsigned space = line.find(' ');
157 >
158 >                unsigned major = strtoul(line.substr(5, dot - 5).c_str(), 0, 10);
159 >                unsigned minor = strtoul(line.substr(dot + 1, space - dot - 1).c_str(),
160 >                        0, 10);
161 >
162 >                if (major > 1)
163 >                {
164 >                        cerr << program << ": Potentially Incompatible Server: HTTP/" <<
165 >                                major << "." << minor << "\n";
166 >
167 >                        return answer;
168 >                }
169 >
170 >                response = code(strtoul(line.substr(space + 1).c_str(), 0, 10));
171 >
172 >                if (response < ok) do line = getline(); while (line != "");
173 >        }
174 >        while (response < ok);
175 >
176 >        do
177 >        {
178 >                line = getline();
179 >
180 >                if (line != "")
181 >                {
182 >                        unsigned colon = line.find(':');
183 >
184 >                        string field = line.substr(0, colon);
185 >                        string value = line.substr(colon + 1);
186 >
187 >                        while (isspace(value[0])) value.erase(0, 1);
188 >
189 >                        if (field == "Content-Type")
190 >                        {
191 >                                type = value;
192 >                        }
193 >                        else if (field == "Content-Length")
194 >                        {
195 >                                length = strtoul(value.c_str(), 0, 10);
196 >                        }
197 >                        else if (field == "Location")
198 >                        {
199 >                                location = value;
200 >                        }
201 >                        else if (field == "Transfer-Encoding")
202 >                        {
203 >                                chunked = value == "chunked";
204 >                        }
205 >                }
206          }
207 +        while (line != "");
208 +
209 +        switch (response)
210 +        {
211 +        case ok:
212 +                if (debug) cerr << "response = " << response << "\n";
213 +                answer = true;
214 +                break;
215 +        case choices:
216 +        case moved:
217 +        case found:
218 +                if (debug) cerr << "response = " << response << "\n"
219 +                        << "location = " << location << "\n";
220 +                location = getLink(location, url);
221 +                break;
222 +        case notfound:
223 +        case internal:
224 +                if (debug) cerr << "response = " << response << "\n";
225 +                break;
226 +        default:
227 +                if (debug) cerr << "response = " << response << "\n";
228 +                if (response <= 299)
229 +                {
230 +                        answer = true;
231 +                }
232 +                else if (response <= 399)
233 +                {
234 +                        location = getLink(location, url);
235 +                }
236 +                break;
237 +        }
238 +
239 +        if (!head && answer) populate();
240  
241          return answer;
242   }
243  
244 + HttpHandler& HttpHandler::getline(string& line, char endline)
245 + {
246 +        unsigned end = page.find(endline);
247 +        unsigned newline = page.find('\n');
248 +
249 +        if (newline < end || end == string::npos)
250 +        {
251 +                end = newline;
252 +        }
253 +
254 +        line = page.substr(0, end);
255 +        page.erase(0, (end == string::npos ? end : end + 1));
256 +
257 +        return *this;
258 + }
259 +
260   void HttpHandler::clear()
261   {
262 <        begin = 0;
262 >        closesocket(http);
263 >
264 >        type = "";
265 >        length = 0;
266 >        location = "";
267          page = "";
268 +        chunked = false;
269   }
270  
271 < void HttpHandler::setJarPath()
271 > void HttpHandler::populate()
272   {
273 <        const string jarFile = "HttpConnector.jar";
181 <        string jarFilePath = jarFile;
182 <
183 <        ifstream fin(jarFilePath.c_str());
184 <        if (!fin.is_open())
273 >        if (!chunked)
274          {
275 <                unsigned end = program.rfind(PATH_SEPARATOR);
276 <                if (end != string::npos)
275 >                unsigned left = length;
276 >
277 >                while (left > 0)
278                  {
279 <                        string path = program.substr(0, end);
279 >                        memset(buffer, 0, BUFSIZ + 1);
280  
281 <                        jarFilePath = path + PATH_SEPARATOR + jarFile;
281 >                        unsigned bytes = left > BUFSIZ ? BUFSIZ : left;
282 >                        unsigned received;
283  
284 <                        fin.open(jarFilePath.c_str());
194 <                        if (!fin.is_open())
284 >                        while (true)
285                          {
286 <                                cerr << program << ": Could not find required file: "
287 <                                        << jarFile << "\n";
288 <                                exit(1);
289 <                        }
290 <                        else
291 <                        {
292 <                                fin.close();
286 >                                if ((received = recv(http, buffer, bytes, 0)) == SOCKET_ERROR)
287 >                                {
288 >                                        error(program + ": Recv");
289 >                                        exit(1);
290 >                                }
291 >                                else if (received != bytes)
292 >                                {
293 >                                        left -= received;
294 >                                        page += buffer;
295 >
296 >                                        memset(buffer, 0, BUFSIZ + 1);
297 >
298 >                                        bytes -= received;
299 >                                }
300 >                                else
301 >                                {
302 >                                        break;
303 >                                }
304                          }
305 +
306 +                        page += buffer;
307 +                        left -= bytes;
308                  }
309 <                else
309 >        }
310 >        else
311 >        {
312 >                unsigned chunk;
313 >
314 >                do
315                  {
316 <                        string envPath = getenv("PATH");
316 >                        chunk = strtoul(getline().c_str(), 0, 16);
317  
318 <                        if (debug) cerr << "envPath = " << envPath << "\n";
318 >                        unsigned left = chunk;
319  
320 <                        unsigned begin = 0;
212 <                        do
320 >                        while (left > 0)
321                          {
322 <                                unsigned end = envPath.find(ENV_SEPARATOR, begin);
215 <                                string path = envPath.substr(begin, end);
216 <
217 <                                if (debug) cerr << "path = " << path << "\n";
322 >                                memset(buffer, 0, BUFSIZ + 1);
323  
324 <                                jarFilePath = path + PATH_SEPARATOR + jarFile;
324 >                                unsigned bytes = left > BUFSIZ ? BUFSIZ : left;
325 >                                unsigned received;
326  
327 <                                fin.open(jarFilePath.c_str());
222 <                                if (fin.is_open())
327 >                                while (true)
328                                  {
329 <                                        fin.close();
330 <                                        break;
329 >                                        if ((received = recv(http, buffer, bytes, 0)) ==
330 >                                                SOCKET_ERROR)
331 >                                        {
332 >                                                error(program + ": Recv");
333 >                                                exit(1);
334 >                                        }
335 >                                        else if (received != bytes)
336 >                                        {
337 >                                                left -= received;
338 >                                                page += buffer;
339 >
340 >                                                memset(buffer, 0, BUFSIZ + 1);
341 >
342 >                                                bytes -= received;
343 >                                        }
344 >                                        else
345 >                                        {
346 >                                                break;
347 >                                        }
348                                  }
349  
350 <                                begin = end != string::npos ? end + 1 : string::npos;
350 >                                page += buffer;
351 >                                left -= bytes;
352                          }
230                        while (begin < envPath.length());
353  
354 <                        if (begin == string::npos)
355 <                        {
234 <                                cerr << program << ": Could not find required file: "
235 <                                        << jarFile << "\n";
236 <                                exit(1);
237 <                        }
354 >                        getline();
355 >                        length += chunk;
356                  }
357 +                while (chunk > 0);
358          }
359 <        else
359 >
360 >        for (unsigned index = 0; index < page.length(); index++)
361          {
362 <                fin.close();
362 >                if (page[index] == '\r' && (index + 1 < page.length()) ? page[index +
363 >                        1] == '\n' : false)
364 >                {
365 >                        page.erase(index, 1);
366 >                }
367 >                else if (page[index] == '\r')
368 >                {
369 >                        page[index] = '\n';
370 >                }
371 >        }
372 > }
373 >
374 > void HttpHandler::putline(const string line)
375 > {
376 >        sprintf(buffer, "%s\r\n", line.c_str());
377 >        if (send(http, buffer, strlen(buffer), 0) == SOCKET_ERROR)
378 >        {
379 >                error(program + ": Send");
380 >                exit(1);
381 >        }
382 > }
383 >
384 > string HttpHandler::getline()
385 > {
386 >        string line;
387 >        char byte;
388 >
389 >        do
390 >        {
391 >                if (recv(http, &byte, 1, 0) == SOCKET_ERROR)
392 >                {
393 >                        error(program + ": Recv");
394 >                }
395 >
396 >                if (byte != '\r' && byte != '\n')
397 >                {
398 >                        line += byte;
399 >                }
400          }
401 +        while (byte != '\n');
402  
403 <        string jarPath = "-Djava.class.path=" + jarFilePath;
403 >        return line;
404 > }
405  
406 < //      this->jarPath = new char[jarPath.length()];
407 < //      strcpy(this->jarPath, jarPath.c_str());
406 > void HttpHandler::error(const string& prefix, bool host)
407 > {
408 > #ifdef _WIN32
409 >        string error;
410 >
411 >        switch (WSAGetLastError())
412 >        {
413 >        case WSAEACCES:
414 >                error = "Permission denied.";
415 >                break;
416 >        case WSAEADDRINUSE:
417 >                error = "Address already in use.";
418 >                break;
419 >        case WSAEADDRNOTAVAIL:
420 >                error = "Cannot assign requested address.";
421 >                break;
422 >        case WSAEAFNOSUPPORT:
423 >                error = "Address family not supported by protocol family.";
424 >                break;
425 >        case WSAEALREADY:
426 >                error = "Operation already in progress.";
427 >                break;
428 >        case WSAECONNABORTED:
429 >                error = "Software caused connection abort.";
430 >                break;
431 >        case WSAECONNREFUSED:
432 >                error = "Connection refused.";
433 >                break;
434 >        case WSAECONNRESET:
435 >                error = "Connection reset by peer.";
436 >                break;
437 >        case WSAEDESTADDRREQ:
438 >                error = "Destination address required.";
439 >                break;
440 >        case WSAEFAULT:
441 >                error = "Bad address.";
442 >                break;
443 >        case WSAEHOSTDOWN:
444 >                error = "Host is down.";
445 >                break;
446 >        case WSAEHOSTUNREACH:
447 >                error = "No route to host.";
448 >                break;
449 >        case WSAEINPROGRESS:
450 >                error = "Operation now in progress.";
451 >                break;
452 >        case WSAEINTR:
453 >                error = "Interrupted function call.";
454 >                break;
455 >        case WSAEINVAL:
456 >                error = "Invalid argument.";
457 >                break;
458 >        case WSAEISCONN:
459 >                error = "Socket is already connected.";
460 >                break;
461 >        case WSAEMFILE:
462 >                error = "Too many open files.";
463 >                break;
464 >        case WSAEMSGSIZE:
465 >                error = "Message too long.";
466 >                break;
467 >        case WSAENETDOWN:
468 >                error = "Network is down.";
469 >                break;
470 >        case WSAENETRESET:
471 >                error = "Network dropped connection on reset.";
472 >                break;
473 >        case WSAENETUNREACH:
474 >                error = "Network is unreachable.";
475 >                break;
476 >        case WSAENOBUFS:
477 >                error = "No buffer space available.";
478 >                break;
479 >        case WSAENOPROTOOPT:
480 >                error = "Bad protocol option.";
481 >                break;
482 >        case WSAENOTCONN:
483 >                error = "Socket is not connected.";
484 >                break;
485 >        case WSAENOTSOCK:
486 >                error = "Socket operation on non-socket.";
487 >                break;
488 >        case WSAEOPNOTSUPP:
489 >                error = "Operation not supported.";
490 >                break;
491 >        case WSAEPFNOSUPPORT:
492 >                error = "Protocol family not supported.";
493 >                break;
494 >        case WSAEPROCLIM:
495 >                error = "Too many processes.";
496 >                break;
497 >        case WSAEPROTONOSUPPORT:
498 >                error = "Protocol not supported.";
499 >                break;
500 >        case WSAEPROTOTYPE:
501 >                error = "Protocol wrong type for socket.";
502 >                break;
503 >        case WSAESHUTDOWN:
504 >                error = "Cannot send after socket shutdown.";
505 >                break;
506 >        case WSAESOCKTNOSUPPORT:
507 >                error = "Socket type not supported.";
508 >                break;
509 >        case WSAETIMEDOUT:
510 >                error = "Connection timed out.";
511 >                break;
512 >        case WSATYPE_NOT_FOUND:
513 >                error = "Class type not found.";
514 >                break;
515 >        case WSAEWOULDBLOCK:
516 >                error = "Resource temporarily unavailable.";
517 >                break;
518 >        case WSAHOST_NOT_FOUND:
519 >                error = "Host not found.";
520 >                break;
521 >        case WSA_INVALID_HANDLE:
522 >                error = "Specified event object handle is invalid.";
523 >                break;
524 >        case WSA_INVALID_PARAMETER:
525 >                error = "One or more parameters are invalid.";
526 >                break;
527 > //      case WSAINVALIDPROCTABLE:
528 > //              error = "Invalid procedure table from service provider.";
529 > //              break;
530 > //      case WSAINVALIDPROVIDER:
531 > //              error = "Invalid service provider version number.";
532 > //              break;
533 >        case WSA_IO_INCOMPLETE:
534 >                error = "Overlapped I/O event object not in signaled state.";
535 >                break;
536 >        case WSA_IO_PENDING:
537 >                error = "Overlapped operations will complete later.";
538 >                break;
539 >        case WSA_NOT_ENOUGH_MEMORY:
540 >                error = "Insufficient memory available.";
541 >                break;
542 >        case WSANOTINITIALISED:
543 >                error = "Successful WSAStartup not yet performed.";
544 >                break;
545 >        case WSANO_DATA:
546 >                error = "Valid name, no data record of requested type.";
547 >                break;
548 >        case WSANO_RECOVERY:
549 >                error = "This is a non-recoverable error.";
550 >                break;
551 > //      case WSAPROVIDERFAILEDINIT:
552 > //              error = "Unable to initialize a service provider.";
553 > //              break;
554 >        case WSASYSCALLFAILURE:
555 >                error = "System call failure.";
556 >                break;
557 >        case WSASYSNOTREADY:
558 >                error = "Network subsystem is unavailable.";
559 >                break;
560 >        case WSATRY_AGAIN:
561 >                error = "Non-authoritative host not found.";
562 >                break;
563 >        case WSAVERNOTSUPPORTED:
564 >                error = "WINSOCK.DLL version out of range.";
565 >                break;
566 >        case WSAEDISCON:
567 >                error = "Graceful shutdown in progress.";
568 >                break;
569 >        case WSA_OPERATION_ABORTED:
570 >                error = "Overlapped operation aborted.";
571 >                break;
572 >        default:
573 >                error = "Unknown error.";
574 >                break;
575 >        }
576 >
577 >        cerr << prefix << ": " << error << "\n";
578 > #else
579 >        if (host)
580 >        {
581 >                herror(prefix.c_str());
582 >        }
583 >        else
584 >        {
585 >                perror(prefix.c_str());
586 >        }
587 > #endif // _WIN32
588   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines