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

Contents of /trunk/Src/wptHTTP.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 181 - (show 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 /* 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