/[winpt]/trunk/Src/wptHTTP.cpp
ViewVC logotype

Annotation of /trunk/Src/wptHTTP.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 214 - (hide annotations)
Sun May 14 18:40:36 2006 UTC (18 years, 9 months ago) by twoaday
File size: 12145 byte(s)
2006-05-14  Timo Schulz  <ts@g10code.de>
                                                                                
        * wptKeyCache.cpp (gpg_keycache_update_attr): Parse
        preferred keyserver URL.
        * wptHTTP.cpp (extractHostInfo): Fix segv.
        * wptGPGUtil.cpp (gpg_find_key_subpacket): Ignore default
        gpg.conf.
        * wptKeyserverSearchDlg.cpp (search_hkp_keys): Do not
        assume an existing user id.
        * wptPassphraseCB.cpp (passphrase_cb): Automatic cancel
        if no passphrase is available.

(for complete list of changes, see Src/ChangeLog)

About to release 0.12.1


1 twoaday 181 /* wptHTTP.cpp - Generic HTTP support
2     * Copyright (C) 2004, 2005, 2006 Timo Schulz
3     *
4     * This file is part of WinPT.
5     *
6     * WinPT is free software; you can redistribute it and/or
7     * modify it under the terms of the GNU General Public License
8     * as published by the Free Software Foundation; either version 2
9     * of the License, or (at your option) any later version.
10     *
11     * WinPT is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     * General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with WinPT; if not, write to the Free Software Foundation,
18     * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20     #ifdef HAVE_CONFIG_H
21     #include <config.h>
22     #endif
23    
24     #include <stdio.h>
25     #include <stdio.h>
26     #include <stdlib.h>
27     #include <string.h>
28     #include <windows.h>
29     #include <ctype.h>
30     #include <errno.h>
31    
32     #include "wptHTTP.h"
33     #include "wptTypes.h"
34     #include "wptErrors.h"
35    
36     #define free_if_malloc(buf) if ((buf)) { free ((buf)); (buf) = NULL; }
37    
38     /* Empty constructur to allow advanced requests. */
39     wHTTP::wHTTP (void)
40     {
41     reset ();
42     }
43    
44    
45     /* Constructur to allow alternative syntax. */
46     wHTTP::wHTTP (const char *_host, int _port, const char *_url)
47     {
48     reset ();
49     this->host = strdup (_host);
50     this->port = _port;
51     this->url = strdup (_url);
52     if (!sendRequest (_host, _port, _url))
53     parseResponse (&statcode);
54    
55     }
56    
57    
58     /* Standard constructur. */
59     wHTTP::wHTTP (const char *_url)
60     {
61     reset ();
62     extractHostInfo (_url, &this->host, &this->url);
63     /* XXX: if the connection fails, return the error code to the user. */
64     if (!sendRequest (this->host, this->port, this->url))
65     parseResponse (&statcode);
66     }
67    
68    
69     /* Reset object contents for first use. */
70     void
71     wHTTP::reset (void)
72     {
73     ver = 1;
74     port = 80;
75     host = url = NULL;
76     req_headers = resp_headers = NULL;
77     fd = statcode = 0;
78     method = HTTP_GET;
79     nleft = -1;
80 twoaday 200 error = 0;
81 twoaday 181 }
82    
83    
84     /* Perform a HTTP 'HEAD' request. */
85     int
86     wHTTP::head (const char *_url)
87     {
88     free_if_malloc (host);
89     free_if_malloc (url);
90    
91     extractHostInfo (_url, &this->host, &this->url);
92     method = HTTP_HEAD;
93    
94     if (!sendRequest (host, port, url))
95     parseResponse (&statcode);
96    
97     return 0;
98     }
99    
100    
101     /* Perform a HTTP 'GET' request. */
102     int
103     wHTTP::get (const char *_url)
104     {
105     free_if_malloc (host);
106     free_if_alloc (url);
107    
108     extractHostInfo (_url, &this->host, &this->url);
109    
110     method = HTTP_GET;
111     if (!sendRequest (this->host, this->port, this->url))
112     parseResponse (&statcode);
113    
114     return 0;
115     }
116    
117    
118     /* Return HTTP status code. */
119     int
120     wHTTP::getStatusCode (void)
121     {
122     return statcode;
123     }
124    
125    
126     /* Return MIME content type. */
127     const char*
128     wHTTP::getContentType (void)
129     {
130     const char *type = NULL;
131    
132     findHeader (resp_headers, "Content-Type", &type);
133     return type;
134     }
135    
136    
137     /* Return content length. */
138     unsigned int
139     wHTTP::getContentLength (void)
140     {
141     const char *len = NULL;
142    
143     if (findHeader (resp_headers, "Content-Length", &len))
144     return strtoul (len, NULL, 10);
145     return 0;
146     }
147    
148    
149     void
150     wHTTP::addHeader (http_head_t *root, const char *val)
151     {
152     http_head_t n, t;
153    
154     t = (http_head_t)calloc (1, sizeof *t+strlen (val)+2);
155     if (!t)
156     BUG (0);
157     strcpy (t->d, val);
158    
159     if (!*root)
160     *root = t;
161     else {
162     for (n = *root; n->next; n=n->next)
163     ;
164     n->next = t;
165     }
166     }
167    
168    
169     bool
170     wHTTP::findHeader (http_head_t root,
171     const char *name, const char **val)
172     {
173     http_head_t n;
174     char *p;
175    
176     *val = NULL;
177     for (n = root; n; n = n->next) {
178     if (strlen (n->d) >= strlen (name) &&
179     strstr (n->d, name)) {
180     p = strchr (n->d, ':');
181     *val = p? n->d + (p - n->d + 1 + 1) : NULL;
182     return true;
183     }
184     }
185     return false;
186     }
187    
188    
189     int
190     wHTTP::connect (const char *_host, int _port)
191     {
192     struct hostent *hp;
193     struct sockaddr_in srv;
194     unsigned long addr = 0;
195     int i = 1;
196    
197     memset (&srv, 0, sizeof srv);
198     srv.sin_port = htons ((unsigned short)_port);
199     srv.sin_family = AF_INET;
200    
201     if (isalpha (*_host)) {
202     hp = gethostbyname (_host);
203 twoaday 200 if (!hp) {
204     this->error = (int)WSAGetLastError ();
205 twoaday 181 return WPTERR_WINSOCK_CONNECT;
206 twoaday 200 }
207 twoaday 181 memcpy (&srv.sin_addr, hp->h_addr, hp->h_length);
208     }
209     else {
210     addr = inet_addr (_host);
211 twoaday 200 if (addr == INADDR_NONE) {
212     this->error = (int)WSAGetLastError ();
213 twoaday 181 return WPTERR_WINSOCK_CONNECT;
214 twoaday 200 }
215 twoaday 181 memcpy (&srv.sin_addr, &addr, sizeof addr);
216     }
217    
218     fd = socket (AF_INET, SOCK_STREAM, 0);
219 twoaday 200 if (fd < 0) {
220     this->error = (int)WSAGetLastError ();
221 twoaday 181 return WPTERR_WINSOCK_SOCKET;
222 twoaday 200 }
223 twoaday 181
224     if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
225     (const char*)&i, sizeof i)) {
226     closesocket (fd);
227     fd = 0;
228 twoaday 200 this->error = (int)WSAGetLastError ();
229 twoaday 181 return WPTERR_WINSOCK_SOCKET;
230     }
231    
232     if (::connect (fd, (struct sockaddr *)&srv, sizeof srv)) {
233     closesocket (fd);
234     fd = 0;
235 twoaday 200 this->error = (int)WSAGetLastError ();
236 twoaday 181 return WPTERR_WINSOCK_CONNECT;
237     }
238    
239     return 0;
240     }
241    
242    
243     int
244     wHTTP::isDataAvailable (int _fd)
245     {
246     struct timeval tv;
247     fd_set inp;
248     int n;
249    
250     FD_ZERO (&inp);
251     FD_SET (_fd, &inp);
252     tv.tv_sec = 1;
253     tv.tv_usec = 0;
254    
255     n = select (_fd+1, &inp, NULL, NULL, &tv);
256     if (n && FD_ISSET (_fd, &inp))
257     return n;
258     return 0;
259     }
260    
261    
262     int
263     wHTTP::readLine (char *buf, unsigned int nbuf,
264     int nonblock, int *nn, int *eof)
265     {
266     char c;
267     int n, i;
268    
269     if (nn)
270     *nn = 0;
271     if (eof)
272     *eof = 0;
273     i = 0;
274     do {
275     if (nonblock == 1 && isDataAvailable (fd) == 0) {
276     buf[i++] = '\0';
277     i = -1;
278     break;
279     }
280     n = recv (fd, &c, 1, 0);
281     if (n == -1)
282     break;
283     if (n == 0 || nbuf == 0 || c == '\n') {
284     if (n == 0) {
285     if (eof)
286     *eof = 1;
287     buf[i++] = '\0';
288     }
289     else {
290     buf[i++] = c;
291     buf[i] = '\0';
292     }
293     break;
294     }
295     else {
296     buf[i++] = c;
297     nbuf--;
298     }
299     } while (n > 0 && i != -1);
300    
301     if (nn)
302     *nn = i;
303     return 0;
304     }
305    
306    
307    
308     /* Extract the host from the given url @url. Return the host in
309     @host and also return the resource part of the url in @new_url. */
310     int
311     wHTTP::extractHostInfo (const char *_url, char **_host, char **new_url)
312     {
313     char *p;
314     char tmpbuf[512];
315    
316     *_host = NULL;
317     *new_url = NULL;
318    
319     /* XXX: do not use static buffers. */
320     memset (tmpbuf, 0, sizeof (tmpbuf));
321 twoaday 214 strncpy (tmpbuf, _url, sizeof (tmpbuf)-1);
322 twoaday 181
323     p = "http://";
324     if (strlen (_url) < 10 || strncmp (_url, p, 7))
325     return WPTERR_GENERAL;
326     _url += strlen (p);
327     p = strtok (tmpbuf+7, "/");
328     if (!p)
329     return WPTERR_GENERAL;
330     *_host = strdup (p);
331     p = strchr (_url, '/');
332     if (!p) {
333     free_if_malloc (*_host);
334     return WPTERR_GENERAL;
335     }
336     *new_url = strdup (p);
337     return 0;
338     }
339    
340    
341     /* Add a request header. */
342     int
343     wHTTP::addRequestHeader (const char *name, const char *val)
344     {
345     char *p;
346     char *fmt = "%s: %s";
347    
348 twoaday 214 p = (char*) malloc (strlen (name)+strlen (val)+strlen (fmt)+4);
349 twoaday 181 sprintf (p, fmt, name, val);
350     addHeader (&req_headers, p);
351     free_if_malloc (p);
352    
353     return 0;
354     }
355    
356    
357     void
358     wHTTP::setVersion (int _ver)
359     {
360     if (_ver > 9)
361     _ver = 0;
362     this->ver = _ver;
363     }
364    
365    
366     int
367     wHTTP::addRequestHeader (const char *name, unsigned int val)
368     {
369     char buf[32];
370    
371     sprintf (buf, "%lu", (DWORD)val);
372     return addRequestHeader (name, buf);
373     }
374    
375    
376     /* Prepare the request resource @url and send
377     it to host @host (port @port). */
378     int
379     wHTTP::sendRequest (const char *_host, int _port, const char *_url)
380     {
381     const char *id[] = {"GET", "HEAD", "PUT", "POST"};
382     http_head_t h;
383     const char *h_head;
384     char *p;
385     int n;
386     int rc;
387    
388     if (!this->fd) {
389     rc = connect (_host, _port);
390     if (rc)
391     return rc;
392     }
393    
394     if (*_url == '/')
395 twoaday 214 _url++;
396 twoaday 181 if (_url == NULL)
397     _url = "";
398    
399     addRequestHeader ("Host", _host);
400     if (ver < 1)
401     addRequestHeader ("Connection", "close");
402    
403     n = 0;
404     for (h = req_headers; h; h = h->next)
405     n += strlen (h->d) + 2 + 1;
406     h_head = "%s /%s HTTP/1.%d\r\n";
407 twoaday 214 n += strlen (id[method]) + strlen (h_head)
408     + strlen (_url) + n + 2 + 1 + 4;
409     p = (char*)calloc (1, n+1);
410 twoaday 181 if (!p)
411     BUG (0);
412 twoaday 214 sprintf (p, h_head, id[method], _url, ver);
413 twoaday 181 for (h = req_headers; h; h = h->next) {
414     strcat (p, h->d);
415     strcat (p, "\r\n");
416     }
417     strcat (p, "\r\n");
418     n = send (fd, p, strlen (p), 0);
419     free_if_malloc (p);
420     return n > 0? 0 : WPTERR_GENERAL;
421     }
422    
423    
424     /* Parse all response resp_headers. */
425     int
426     wHTTP::parseHeaders (http_head_t *r_head)
427     {
428     char buf[300];
429     int nn;
430     int rc;
431    
432     if (!r_head)
433     return WPTERR_GENERAL;
434    
435     do {
436     rc = readLine (buf, 299, 1, &nn, NULL);
437     if (rc)
438     return rc;
439     if (nn == 2)
440     break; /* reach empty line */
441     addHeader (r_head, buf);
442     } while (rc == 0);
443     return 0;
444     }
445    
446    
447     /* Read data from the response and write it to @out. */
448     int
449     wHTTP::readData (FILE *out)
450     {
451     const char *val;
452     char buf[1024+1];
453     int nlen = 0, nn = 0, n, eof=0;
454     int rc = 0;
455    
456     if (this->fd == 0 || this->resp_headers == NULL)
457     return -1;
458    
459     nlen = getContentLength ();
460     if (nlen == 0) {
461     if (!findHeader (resp_headers, "Connection", &val) ||
462     strnicmp (val, "close", 4))
463     return WPTERR_GENERAL;
464     }
465    
466     val = getContentType ();
467     if (!val)
468     return WPTERR_GENERAL;
469     if (strnicmp (val, "text", 4)) { /* binary */
470     do {
471     n = recv (fd, buf, nlen > 1024? 1024 : nlen, 0);
472     if (n == -1)
473     return SOCKET_ERROR;
474     if (n == 0)
475     break;
476     nlen -= n;
477     fwrite (buf, 1, n, out);
478     } while (nlen > 0);
479     return 0;
480     }
481    
482     do {
483     rc = readLine (buf, 1024, 1, &n, &eof);
484     if (rc)
485     return rc;
486     if (n > 0)
487     fwrite (buf, 1, n, out);
488     if (nlen > 0) {
489     nn += n;
490     if (nlen == nn)
491     break;
492     }
493     } while (eof == 0);
494    
495     return 0;
496     }
497    
498    
499     /* Parse the HTTP response line. */
500     int
501     wHTTP::parseResponse (int *_statcode)
502     {
503     http_head_t n;
504     const char *tmp, *p;
505     char buf[300];
506     int code = 0, nn = 0;
507     int rc;
508    
509     *_statcode = 0;
510     rc = readLine (buf, 299, 1, &nn, NULL);
511     if (rc)
512     return rc;
513    
514     tmp = "HTTP/1.";
515     if (strlen (buf) < 8 || strncmp (buf, tmp, strlen (tmp)))
516     return WPTERR_GENERAL;
517     p = buf;
518     p += strlen (tmp)+1 + 1; /* skip HTTP/1.x and WS */
519     *_statcode = atoi (p);
520     if (tmp == 0)
521     return WPTERR_GENERAL;
522     p += 3 + 1; /* number + WS */
523    
524     if (code == HTTP_STAT_400 ||
525     code == HTTP_STAT_403 ||
526     code == HTTP_STAT_404 ||
527     code == HTTP_STAT_405)
528     return WPTERR_GENERAL;
529    
530     while (resp_headers) {
531     n = resp_headers->next;
532     free (resp_headers);
533     resp_headers = n;
534     }
535     resp_headers = NULL;
536     rc = parseHeaders (&resp_headers);
537     if (rc)
538     return rc;
539     return 0;
540     }
541    
542    
543     /* Destroy HTTP object. */
544     wHTTP::~wHTTP (void)
545     {
546     http_head_t h;
547    
548     while (resp_headers) {
549     h = resp_headers->next;
550     free (resp_headers);
551     resp_headers = h;
552     }
553     while (req_headers) {
554     h = req_headers->next;
555     free (req_headers);
556     req_headers = h;
557     }
558     free_if_malloc (url);
559     free_if_malloc (host);
560 twoaday 200 if (fd != 0) {
561 twoaday 181 closesocket (fd);
562 twoaday 200 fd = 0;
563     }
564 twoaday 181 }
565    
566    
567 twoaday 200 /* Read @buflen bytes from the http stream into the buffer @buf. */
568 twoaday 181 int
569     wHTTP::read (void *buf, unsigned int buflen)
570     {
571     int n;
572    
573     if (this->fd == 0 || this->resp_headers == NULL)
574     return -1;
575     if (method != HTTP_GET)
576     return -1;
577    
578     if (nleft == -1)
579     nleft = getContentLength ();
580     if ((int)buflen > nleft)
581     buflen = nleft;
582     if (nleft == 0)
583     return -1;
584    
585     n = recv (fd, (char*)buf, (int)buflen, 0);
586     if (n > 0) {
587     nleft -= n;
588     if (nleft < 0) nleft = 0;
589     }
590     return n;
591     }
592    
593    
594 twoaday 200 /* Write the buffer @buf to the http stream. */
595 twoaday 181 int
596     wHTTP::write (const void *buf, unsigned buflen)
597     {
598     if (this->fd == 0)
599     return -1;
600     if (method == HTTP_GET || method == HTTP_HEAD)
601     return -1;
602     return send (fd, (const char*)buf, (int)buflen, 0);
603     }
604 twoaday 200
605    
606     /* Return the winsock specific error code. */
607     int wHTTP::getErrorCode (void)
608     {
609     return error;
610     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26