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

Annotation of /trunk/Src/wptHTTP.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 181 - (hide annotations)
Tue Mar 14 11:01:22 2006 UTC (18 years, 11 months ago) by twoaday
File size: 11672 byte(s)
2006-03-12  Timo Schulz  <ts@g10code.de>
 
        * wptGPG.cpp (gnupg_load_config): Search for 'ask-cert-expire'.
        * wptKeyPropsDlg.cpp (display_key_info): Automatically update
        sym algorithm preferences if needed.
        * wptKeysignDlg.cpp (date_is_today): New.
        (keysign_dlg_proc): Only allow to set cert expire date if
        the option was found.
        * wptGPGPrefsDlg.cpp (gpgprefs_dlg_proc): Allow to set
        'ask-cert-expire'.
         


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     }
81    
82    
83     /* Perform a HTTP 'HEAD' request. */
84     int
85     wHTTP::head (const char *_url)
86     {
87     free_if_malloc (host);
88     free_if_malloc (url);
89    
90     extractHostInfo (_url, &this->host, &this->url);
91     method = HTTP_HEAD;
92    
93     if (!sendRequest (host, port, url))
94     parseResponse (&statcode);
95    
96     return 0;
97     }
98    
99    
100     /* Perform a HTTP 'GET' request. */
101     int
102     wHTTP::get (const char *_url)
103     {
104     free_if_malloc (host);
105     free_if_alloc (url);
106    
107     extractHostInfo (_url, &this->host, &this->url);
108    
109     method = HTTP_GET;
110     if (!sendRequest (this->host, this->port, this->url))
111     parseResponse (&statcode);
112    
113     return 0;
114     }
115    
116    
117     /* Return HTTP status code. */
118     int
119     wHTTP::getStatusCode (void)
120     {
121     return statcode;
122     }
123    
124    
125     /* Return MIME content type. */
126     const char*
127     wHTTP::getContentType (void)
128     {
129     const char *type = NULL;
130    
131     findHeader (resp_headers, "Content-Type", &type);
132     return type;
133     }
134    
135    
136     /* Return content length. */
137     unsigned int
138     wHTTP::getContentLength (void)
139     {
140     const char *len = NULL;
141    
142     if (findHeader (resp_headers, "Content-Length", &len))
143     return strtoul (len, NULL, 10);
144     return 0;
145     }
146    
147    
148     void
149     wHTTP::addHeader (http_head_t *root, const char *val)
150     {
151     http_head_t n, t;
152    
153     t = (http_head_t)calloc (1, sizeof *t+strlen (val)+2);
154     if (!t)
155     BUG (0);
156     strcpy (t->d, val);
157    
158     if (!*root)
159     *root = t;
160     else {
161     for (n = *root; n->next; n=n->next)
162     ;
163     n->next = t;
164     }
165     }
166    
167    
168     bool
169     wHTTP::findHeader (http_head_t root,
170     const char *name, const char **val)
171     {
172     http_head_t n;
173     char *p;
174    
175     *val = NULL;
176     for (n = root; n; n = n->next) {
177     if (strlen (n->d) >= strlen (name) &&
178     strstr (n->d, name)) {
179     p = strchr (n->d, ':');
180     *val = p? n->d + (p - n->d + 1 + 1) : NULL;
181     return true;
182     }
183     }
184     return false;
185     }
186    
187    
188     int
189     wHTTP::connect (const char *_host, int _port)
190     {
191     struct hostent *hp;
192     struct sockaddr_in srv;
193     unsigned long addr = 0;
194     int i = 1;
195    
196     memset (&srv, 0, sizeof srv);
197     srv.sin_port = htons ((unsigned short)_port);
198     srv.sin_family = AF_INET;
199    
200     if (isalpha (*_host)) {
201     hp = gethostbyname (_host);
202     if (!hp)
203     return WPTERR_WINSOCK_CONNECT;
204     memcpy (&srv.sin_addr, hp->h_addr, hp->h_length);
205     }
206     else {
207     addr = inet_addr (_host);
208     if (addr == INADDR_NONE)
209     return WPTERR_WINSOCK_CONNECT;
210     memcpy (&srv.sin_addr, &addr, sizeof addr);
211     }
212    
213     fd = socket (AF_INET, SOCK_STREAM, 0);
214     if (fd < 0)
215     return WPTERR_WINSOCK_SOCKET;
216    
217     if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
218     (const char*)&i, sizeof i)) {
219     closesocket (fd);
220     fd = 0;
221     return WPTERR_WINSOCK_SOCKET;
222     }
223    
224     if (::connect (fd, (struct sockaddr *)&srv, sizeof srv)) {
225     closesocket (fd);
226     fd = 0;
227     return WPTERR_WINSOCK_CONNECT;
228     }
229    
230     return 0;
231     }
232    
233    
234     int
235     wHTTP::isDataAvailable (int _fd)
236     {
237     struct timeval tv;
238     fd_set inp;
239     int n;
240    
241     FD_ZERO (&inp);
242     FD_SET (_fd, &inp);
243     tv.tv_sec = 1;
244     tv.tv_usec = 0;
245    
246     n = select (_fd+1, &inp, NULL, NULL, &tv);
247     if (n && FD_ISSET (_fd, &inp))
248     return n;
249     return 0;
250     }
251    
252    
253     int
254     wHTTP::readLine (char *buf, unsigned int nbuf,
255     int nonblock, int *nn, int *eof)
256     {
257     char c;
258     int n, i;
259    
260     if (nn)
261     *nn = 0;
262     if (eof)
263     *eof = 0;
264     i = 0;
265     do {
266     if (nonblock == 1 && isDataAvailable (fd) == 0) {
267     buf[i++] = '\0';
268     i = -1;
269     break;
270     }
271     n = recv (fd, &c, 1, 0);
272     if (n == -1)
273     break;
274     if (n == 0 || nbuf == 0 || c == '\n') {
275     if (n == 0) {
276     if (eof)
277     *eof = 1;
278     buf[i++] = '\0';
279     }
280     else {
281     buf[i++] = c;
282     buf[i] = '\0';
283     }
284     break;
285     }
286     else {
287     buf[i++] = c;
288     nbuf--;
289     }
290     } while (n > 0 && i != -1);
291    
292     if (nn)
293     *nn = i;
294     return 0;
295     }
296    
297    
298    
299     /* Extract the host from the given url @url. Return the host in
300     @host and also return the resource part of the url in @new_url. */
301     int
302     wHTTP::extractHostInfo (const char *_url, char **_host, char **new_url)
303     {
304     char *p;
305     char tmpbuf[512];
306    
307     *_host = NULL;
308     *new_url = NULL;
309    
310     /* XXX: do not use static buffers. */
311     memset (tmpbuf, 0, sizeof (tmpbuf));
312     strncpy (tmpbuf, _url, 512);
313    
314     p = "http://";
315     if (strlen (_url) < 10 || strncmp (_url, p, 7))
316     return WPTERR_GENERAL;
317     _url += strlen (p);
318     p = strtok (tmpbuf+7, "/");
319     if (!p)
320     return WPTERR_GENERAL;
321     *_host = strdup (p);
322     p = strchr (_url, '/');
323     if (!p) {
324     free_if_malloc (*_host);
325     return WPTERR_GENERAL;
326     }
327     *new_url = strdup (p);
328     return 0;
329     }
330    
331    
332     /* Add a request header. */
333     int
334     wHTTP::addRequestHeader (const char *name, const char *val)
335     {
336     char *p;
337     char *fmt = "%s: %s";
338    
339     p = (char*) malloc (strlen (name)+strlen (val)+strlen (fmt)+1);
340     sprintf (p, fmt, name, val);
341     addHeader (&req_headers, p);
342     free_if_malloc (p);
343    
344     return 0;
345     }
346    
347    
348     void
349     wHTTP::setVersion (int _ver)
350     {
351     if (_ver > 9)
352     _ver = 0;
353     this->ver = _ver;
354     }
355    
356    
357     int
358     wHTTP::addRequestHeader (const char *name, unsigned int val)
359     {
360     char buf[32];
361    
362     sprintf (buf, "%lu", (DWORD)val);
363     return addRequestHeader (name, buf);
364     }
365    
366    
367     /* Prepare the request resource @url and send
368     it to host @host (port @port). */
369     int
370     wHTTP::sendRequest (const char *_host, int _port, const char *_url)
371     {
372     const char *id[] = {"GET", "HEAD", "PUT", "POST"};
373     http_head_t h;
374     const char *h_head;
375     char *p;
376     int n;
377     int rc;
378    
379     if (!this->fd) {
380     rc = connect (_host, _port);
381     if (rc)
382     return rc;
383     }
384    
385     if (*_url == '/')
386     url++;
387     if (_url == NULL)
388     _url = "";
389    
390     addRequestHeader ("Host", _host);
391     if (ver < 1)
392     addRequestHeader ("Connection", "close");
393    
394     n = 0;
395     for (h = req_headers; h; h = h->next)
396     n += strlen (h->d) + 2 + 1;
397    
398     h_head = "%s /%s HTTP/1.%d\r\n";
399     p = (char*)calloc (1, strlen (id[method]) + strlen (h_head)
400     + strlen (url) + n + 2 + 1 + 4);
401     if (!p)
402     BUG (0);
403     sprintf (p, h_head, id[method], url, ver);
404     for (h = req_headers; h; h = h->next) {
405     strcat (p, h->d);
406     strcat (p, "\r\n");
407     }
408     strcat (p, "\r\n");
409     printf ("p='%s'\n", p);
410     n = send (fd, p, strlen (p), 0);
411     free_if_malloc (p);
412     return n > 0? 0 : WPTERR_GENERAL;
413     }
414    
415    
416     /* Parse all response resp_headers. */
417     int
418     wHTTP::parseHeaders (http_head_t *r_head)
419     {
420     char buf[300];
421     int nn;
422     int rc;
423    
424     if (!r_head)
425     return WPTERR_GENERAL;
426    
427     do {
428     rc = readLine (buf, 299, 1, &nn, NULL);
429     if (rc)
430     return rc;
431     if (nn == 2)
432     break; /* reach empty line */
433     addHeader (r_head, buf);
434     } while (rc == 0);
435     return 0;
436     }
437    
438    
439     /* Read data from the response and write it to @out. */
440     int
441     wHTTP::readData (FILE *out)
442     {
443     const char *val;
444     char buf[1024+1];
445     int nlen = 0, nn = 0, n, eof=0;
446     int rc = 0;
447    
448     if (this->fd == 0 || this->resp_headers == NULL)
449     return -1;
450    
451     nlen = getContentLength ();
452     if (nlen == 0) {
453     if (!findHeader (resp_headers, "Connection", &val) ||
454     strnicmp (val, "close", 4))
455     return WPTERR_GENERAL;
456     }
457    
458     val = getContentType ();
459     if (!val)
460     return WPTERR_GENERAL;
461     if (strnicmp (val, "text", 4)) { /* binary */
462     do {
463     n = recv (fd, buf, nlen > 1024? 1024 : nlen, 0);
464     if (n == -1)
465     return SOCKET_ERROR;
466     if (n == 0)
467     break;
468     nlen -= n;
469     fwrite (buf, 1, n, out);
470     } while (nlen > 0);
471     return 0;
472     }
473    
474     do {
475     rc = readLine (buf, 1024, 1, &n, &eof);
476     if (rc)
477     return rc;
478     if (n > 0)
479     fwrite (buf, 1, n, out);
480     if (nlen > 0) {
481     nn += n;
482     if (nlen == nn)
483     break;
484     }
485     } while (eof == 0);
486    
487     return 0;
488     }
489    
490    
491     /* Parse the HTTP response line. */
492     int
493     wHTTP::parseResponse (int *_statcode)
494     {
495     http_head_t n;
496     const char *tmp, *p;
497     char buf[300];
498     int code = 0, nn = 0;
499     int rc;
500    
501     *_statcode = 0;
502     rc = readLine (buf, 299, 1, &nn, NULL);
503     if (rc)
504     return rc;
505    
506     tmp = "HTTP/1.";
507     if (strlen (buf) < 8 || strncmp (buf, tmp, strlen (tmp)))
508     return WPTERR_GENERAL;
509     p = buf;
510     p += strlen (tmp)+1 + 1; /* skip HTTP/1.x and WS */
511     *_statcode = atoi (p);
512     if (tmp == 0)
513     return WPTERR_GENERAL;
514     p += 3 + 1; /* number + WS */
515    
516     if (code == HTTP_STAT_400 ||
517     code == HTTP_STAT_403 ||
518     code == HTTP_STAT_404 ||
519     code == HTTP_STAT_405)
520     return WPTERR_GENERAL;
521    
522     while (resp_headers) {
523     n = resp_headers->next;
524     free (resp_headers);
525     resp_headers = n;
526     }
527     resp_headers = NULL;
528     rc = parseHeaders (&resp_headers);
529     if (rc)
530     return rc;
531     return 0;
532     }
533    
534    
535     /* Destroy HTTP object. */
536     wHTTP::~wHTTP (void)
537     {
538    
539     http_head_t h;
540    
541     while (resp_headers) {
542     h = resp_headers->next;
543     free (resp_headers);
544     resp_headers = h;
545     }
546     while (req_headers) {
547     h = req_headers->next;
548     free (req_headers);
549     req_headers = h;
550     }
551     free_if_malloc (url);
552     free_if_malloc (host);
553     if (fd != 0)
554     closesocket (fd);
555     }
556    
557    
558     int
559     wHTTP::read (void *buf, unsigned int buflen)
560     {
561     int n;
562    
563     if (this->fd == 0 || this->resp_headers == NULL)
564     return -1;
565     if (method != HTTP_GET)
566     return -1;
567    
568     if (nleft == -1)
569     nleft = getContentLength ();
570     if ((int)buflen > nleft)
571     buflen = nleft;
572     if (nleft == 0)
573     return -1;
574    
575     n = recv (fd, (char*)buf, (int)buflen, 0);
576     if (n > 0) {
577     nleft -= n;
578     if (nleft < 0) nleft = 0;
579     }
580     return n;
581     }
582    
583    
584     int
585     wHTTP::write (const void *buf, unsigned buflen)
586     {
587     if (this->fd == 0)
588     return -1;
589     if (method == HTTP_GET || method == HTTP_HEAD)
590     return -1;
591     return send (fd, (const char*)buf, (int)buflen, 0);
592     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26