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 13 by douglas, 2002-12-06T19:56:56-08:00 vs.
Revision 178 by douglas, 2003-07-05T19:13:12-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 + #ifndef _WIN32
54 + #include <unistd.h>
55 + #include <sys/types.h>
56 + #include <sys/socket.h>
57 + #include <netinet/in.h>
58 + #include <netdb.h>
59 +
60 + #define INVALID_SOCKET -1
61 + #define SOCKET_ERROR -1
62 +
63 + inline int closesocket(SOCKET s) { return close(s); }
64 + #endif
65 +
66   HttpHandler::HttpHandler()
67   {
68 +        buffer = new char[BUFSIZ + 1];
69 +
70   #ifdef _WIN32
71 <        WSADATA data;
57 <        if (WSAStartup(MAKEWORD(2, 0) != 0, &data))
71 >        if (WSAStartup(MAKEWORD(2, 0), &data) != 0)
72          {
73 <                error(program + ": WSAStartup()");
73 >                error(program + ": WSAStartup");
74                  exit(1);
75          }
76   #endif // _WIN32
77  
78 <        begin = 0;
78 >        length = 0;
79 >        chunked = false;
80   }
81  
82   HttpHandler::~HttpHandler()
83   {
84 +        delete [] buffer;
85 +
86   #ifdef _WIN32
87          WSACleanup();
88   #endif // _WIN32
89   }
90  
91 < bool HttpHandler::connect(URL &url, bool head)
91 > bool HttpHandler::handle(URL &url, const string referer, bool head)
92   {
93          bool answer = false;
94  
95 < //      if (status != JNI_ERR)
96 < //      {
97 < //              if (cls != 0)
98 < //              {
99 < //                      if (mid != 0)
100 < //                      {
101 < //                              jstring addressJ = env->NewStringUTF(url.getAddress().c_str());
102 < //                              jint portJ = url.getPort();
103 < //                              jstring pathJ = env->NewStringUTF(url.getPath().c_str());
104 < //                              jstring programNameJ = env->NewStringUTF(programName.c_str());
105 < //                              jstring programVersionJ =
106 < //                                      env->NewStringUTF(programVersion.c_str());
107 <
108 < //                              jstring pageJ = (jstring)env->CallStaticObjectMethod(cls, mid,
109 < //                                      addressJ, portJ, pathJ, programNameJ, programVersionJ);
110 <
111 < //                              const char* pageC = env->GetStringUTFChars(pageJ, 0);
112 < //                              page = pageC;
113 < //                              env->ReleaseStringUTFChars(pageJ, pageC);
114 <
115 < //                              if (page != "unknown host\n" && page != "io exception\n" &&
116 < //                                      page != "bad headers\n") answer = true;
117 < //                      }
118 < //              }
119 < //      }
95 >        if ((http = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
96 >        {
97 >                error(program + ": Socket");
98 >                exit(1);
99 >        }
100 >
101 >        sockaddr_in address;
102 >        hostent* host;
103 >
104 >        address.sin_family = AF_INET;
105 >
106 >        if ((host = gethostbyname(url.getAddress().c_str())) == NULL)
107 >        {
108 >                error(program + ": Host: " + url.getAddress(), true);
109 >                return answer;
110 >        }
111 >
112 >        address.sin_addr = *((in_addr*)*host->h_addr_list);
113 >        address.sin_port = htons(url.getPort());
114 >
115 >        if (connect(http, (sockaddr*)&address, sizeof(sockaddr_in)) ==
116 >                SOCKET_ERROR)
117 >        {
118 >                error(program + ": Connect");
119 >                return answer;
120 >        }
121 >
122 >        if (head)
123 >        {
124 >                putline("HEAD " + url.getPath() + " HTTP/1.1");
125 >        }
126 >        else
127 >        {
128 >                putline("GET " + url.getPath() + " HTTP/1.1");
129 >        }
130 >
131 >        putline("Accept: text/html; text/plain");
132 >        putline("User-Agent: " + agent(true) + ' ' + platform());
133 >
134 >        if (url.getPort() == 80)
135 >        {
136 >                putline("Host: " + url.getAddress());
137 >        }
138 >        else
139 >        {
140 >                char* port = new char[1024];
141 >                sprintf(port, "%u", url.getPort());
142 >
143 >                putline("Host: " + url.getAddress() + ':' + port);
144 >
145 >                delete [] port;
146 >        }
147 >
148 >        if (referer != "")
149 >        {
150 >                putline("Referer: " + referer);
151 >        }
152 >
153 >        putline("Connection: close");
154 >        putline();
155 >
156 >        code response;
157 >        string line;
158 >
159 >        do
160 >        {
161 >                line = getline();
162 >
163 >                if (line.find("HTTP/") != 0)
164 >                {
165 >                        return answer;
166 >                }
167 >
168 >                unsigned dot = line.find('.');
169 >                unsigned space = line.find(' ');
170 >
171 >                unsigned major = strtoul(line.substr(5, dot - 5).c_str(), 0, 10);
172 >                unsigned minor = strtoul(line.substr(dot + 1, space - dot - 1).c_str(),
173 >                        0, 10);
174 >
175 >                if (major > 1)
176 >                {
177 >                        cerr << program << ": Potentially Incompatible Server: HTTP/" <<
178 >                                major << "." << minor << "\n";
179 >
180 >                        return answer;
181 >                }
182 >
183 >                response = code(strtoul(line.substr(space + 1).c_str(), 0, 10));
184 >
185 >                if (response < ok) do line = getline(); while (line != "");
186 >        }
187 >        while (response < ok);
188 >
189 >        do
190 >        {
191 >                line = getline();
192 >
193 >                if (line != "")
194 >                {
195 >                        unsigned colon = line.find(':');
196 >
197 >                        string field = line.substr(0, colon);
198 >                        string value = line.substr(colon + 1);
199 >
200 >                        while (isspace(value[0])) value.erase(0, 1);
201 >
202 >                        if (field == "Content-Type")
203 >                        {
204 >                                type = value;
205 >                        }
206 >                        else if (field == "Content-Length")
207 >                        {
208 >                                length = strtoul(value.c_str(), 0, 10);
209 >                        }
210 >                        else if (field == "Location")
211 >                        {
212 >                                location = value;
213 >                        }
214 >                        else if (field == "Transfer-Encoding")
215 >                        {
216 >                                chunked = value == "chunked";
217 >                        }
218 >                }
219 >        }
220 >        while (line != "");
221 >
222 >        switch (response)
223 >        {
224 >        case ok:
225 >                if (debug) cerr << "response = " << response << "\n";
226 >                answer = true;
227 >                break;
228 >        case choices:
229 >        case moved:
230 >        case found:
231 >                if (debug) cerr << "response = " << response << "\n"
232 >                        << "location = " << location << "\n";
233 >                location = getLink(location, url);
234 >                break;
235 >        case notfound:
236 >        case internal:
237 >                if (debug) cerr << "response = " << response << "\n";
238 >                break;
239 >        default:
240 >                if (debug) cerr << "response = " << response << "\n";
241 >                if (response <= 299)
242 >                {
243 >                        answer = true;
244 >                }
245 >                else if (response <= 399)
246 >                {
247 >                        location = getLink(location, url);
248 >                }
249 >                break;
250 >        }
251 >
252 >        if (!head && answer) populate();
253  
254          return answer;
255   }
256  
257   HttpHandler& HttpHandler::getline(string& line, char endline)
258   {
259 <        int end = page.find(endline, begin);
260 <        int newline = page.find('\n', begin);
259 >        unsigned end = page.find(endline);
260 >        unsigned newline = page.find('\n');
261  
262          if (newline < end || end == string::npos)
263          {
264                  end = newline;
265          }
266  
267 <        line = page.substr(begin, end - begin);
267 >        line = page.substr(0, end);
268 >        page.erase(0, (end == string::npos ? end : end + 1));
269 >
270 >        return *this;
271 > }
272 >
273 > void HttpHandler::clear()
274 > {
275 >        closesocket(http);
276  
277 <        if (end == string::npos)
277 >        type = "";
278 >        length = 0;
279 >        location = "";
280 >        page = "";
281 >        chunked = false;
282 > }
283 >
284 > void HttpHandler::populate()
285 > {
286 >        if (!chunked)
287          {
288 <                begin = end;
288 >                unsigned left = length;
289 >
290 >                while (left > 0)
291 >                {
292 >                        memset(buffer, 0, BUFSIZ + 1);
293 >
294 >                        unsigned bytes = left > BUFSIZ ? BUFSIZ : left;
295 >                        unsigned received;
296 >
297 >                        while (true)
298 >                        {
299 >                                if ((received = recv(http, buffer, bytes, 0)) == SOCKET_ERROR)
300 >                                {
301 >                                        error(program + ": Recv");
302 >                                        exit(1);
303 >                                }
304 >                                else if (received != bytes)
305 >                                {
306 >                                        left -= received;
307 >                                        page += buffer;
308 >
309 >                                        memset(buffer, 0, BUFSIZ + 1);
310 >
311 >                                        bytes -= received;
312 >                                }
313 >                                else
314 >                                {
315 >                                        break;
316 >                                }
317 >                        }
318 >
319 >                        page += buffer;
320 >                        left -= bytes;
321 >                }
322          }
323          else
324          {
325 <                begin = end + 1;
325 >                unsigned chunk;
326 >
327 >                do
328 >                {
329 >                        chunk = strtoul(getline().c_str(), 0, 16);
330 >
331 >                        unsigned left = chunk;
332 >
333 >                        while (left > 0)
334 >                        {
335 >                                memset(buffer, 0, BUFSIZ + 1);
336 >
337 >                                unsigned bytes = left > BUFSIZ ? BUFSIZ : left;
338 >                                unsigned received;
339 >
340 >                                while (true)
341 >                                {
342 >                                        if ((received = recv(http, buffer, bytes, 0)) ==
343 >                                                SOCKET_ERROR)
344 >                                        {
345 >                                                error(program + ": Recv");
346 >                                                exit(1);
347 >                                        }
348 >                                        else if (received != bytes)
349 >                                        {
350 >                                                left -= received;
351 >                                                page += buffer;
352 >
353 >                                                memset(buffer, 0, BUFSIZ + 1);
354 >
355 >                                                bytes -= received;
356 >                                        }
357 >                                        else
358 >                                        {
359 >                                                break;
360 >                                        }
361 >                                }
362 >
363 >                                page += buffer;
364 >                                left -= bytes;
365 >                        }
366 >
367 >                        getline();
368 >                        length += chunk;
369 >                }
370 >                while (chunk > 0);
371          }
372  
373 <        return *this;
373 >        for (unsigned index = 0; index < page.length(); index++)
374 >        {
375 >                if (page[index] == '\r' && (index + 1 < page.length()) ? page[index +
376 >                        1] == '\n' : false)
377 >                {
378 >                        page.erase(index, 1);
379 >                }
380 >                else if (page[index] == '\r')
381 >                {
382 >                        page[index] = '\n';
383 >                }
384 >        }
385   }
386  
387 < bool HttpHandler::good()
387 > void HttpHandler::putline(const string line)
388   {
389 <        bool answer = true;
390 <
135 <        if (begin >= page.length())
136 <        {
137 <                answer = false;
138 <        }
139 <        else if (begin == string::npos)
389 >        sprintf(buffer, "%s\r\n", line.c_str());
390 >        if (send(http, buffer, strlen(buffer), 0) == SOCKET_ERROR)
391          {
392 <                answer = false;
392 >                error(program + ": Send");
393 >                exit(1);
394          }
143
144        return answer;
395   }
396  
397 < void HttpHandler::clear()
397 > string HttpHandler::getline()
398   {
399 <        begin = 0;
400 <        page = "";
399 >        string line;
400 >        char byte;
401 >
402 >        do
403 >        {
404 >                if (recv(http, &byte, 1, 0) == SOCKET_ERROR)
405 >                {
406 >                        error(program + ": Recv");
407 >                }
408 >
409 >                if (byte != '\r' && byte != '\n')
410 >                {
411 >                        line += byte;
412 >                }
413 >        }
414 >        while (byte != '\n');
415 >
416 >        return line;
417   }
418  
419 < void HttpHandler::error(const string prefix, bool host)
419 > void HttpHandler::error(const string& prefix, bool host)
420   {
421   #ifdef _WIN32
422          string error;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines