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

Contents of /trunk/Src/wptHTTP.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 200 - (show annotations)
Mon Apr 17 09:12:50 2006 UTC (18 years, 10 months ago) by twoaday
File size: 12147 byte(s)
2006-04-16  Timo Schulz  <ts@g10code.de>
 
        * wptHTTP.cpp (getErrorCode): New.
        (connect): Store winsock error code.
        * wptGPGMEData.cpp (is_armor_header): New.
        * wptGPG.cpp (check_gnupg_engine): Free context.
        (gnupg_backup_keyrings): Do not use global vars.
        * wptGPGUtil.cpp (gpg_export_seckey): Export in ascii format.
         
2006-04-15  Timo Schulz  <ts@g10code.de>
 
        * wptKeyManager.cpp (km_get_key): New.
        (km_key_show_revoc_info): New.
        * wptKeyRevokeDlg.cpp (key_revoke_dlg): Cleanups.
        (on_init_dialog): New.
        * wptKeyManagerDlg.cpp (key_manager_dlg_proc): Factour
        out some common code and use km_get_key() instead.
        * wptKeyEditDlgs.cpp (do_init_keylist): Change second
        param type. Change all callers.
        * wptKeyEdit.cpp (addNotation): New.
        * wptKeyEditCB.cpp (editkey_command_handler): Remove 'step'
        param everywhere. Change all callers.


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 error = 0;
81 }
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 if (!hp) {
204 this->error = (int)WSAGetLastError ();
205 return WPTERR_WINSOCK_CONNECT;
206 }
207 memcpy (&srv.sin_addr, hp->h_addr, hp->h_length);
208 }
209 else {
210 addr = inet_addr (_host);
211 if (addr == INADDR_NONE) {
212 this->error = (int)WSAGetLastError ();
213 return WPTERR_WINSOCK_CONNECT;
214 }
215 memcpy (&srv.sin_addr, &addr, sizeof addr);
216 }
217
218 fd = socket (AF_INET, SOCK_STREAM, 0);
219 if (fd < 0) {
220 this->error = (int)WSAGetLastError ();
221 return WPTERR_WINSOCK_SOCKET;
222 }
223
224 if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
225 (const char*)&i, sizeof i)) {
226 closesocket (fd);
227 fd = 0;
228 this->error = (int)WSAGetLastError ();
229 return WPTERR_WINSOCK_SOCKET;
230 }
231
232 if (::connect (fd, (struct sockaddr *)&srv, sizeof srv)) {
233 closesocket (fd);
234 fd = 0;
235 this->error = (int)WSAGetLastError ();
236 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 strncpy (tmpbuf, _url, 512);
322
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 p = (char*) malloc (strlen (name)+strlen (val)+strlen (fmt)+1);
349 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 url++;
396 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
407 h_head = "%s /%s HTTP/1.%d\r\n";
408 p = (char*)calloc (1, strlen (id[method]) + strlen (h_head)
409 + strlen (url) + n + 2 + 1 + 4);
410 if (!p)
411 BUG (0);
412 sprintf (p, h_head, id[method], url, ver);
413 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 printf ("p='%s'\n", p);
419 n = send (fd, p, strlen (p), 0);
420 free_if_malloc (p);
421 return n > 0? 0 : WPTERR_GENERAL;
422 }
423
424
425 /* Parse all response resp_headers. */
426 int
427 wHTTP::parseHeaders (http_head_t *r_head)
428 {
429 char buf[300];
430 int nn;
431 int rc;
432
433 if (!r_head)
434 return WPTERR_GENERAL;
435
436 do {
437 rc = readLine (buf, 299, 1, &nn, NULL);
438 if (rc)
439 return rc;
440 if (nn == 2)
441 break; /* reach empty line */
442 addHeader (r_head, buf);
443 } while (rc == 0);
444 return 0;
445 }
446
447
448 /* Read data from the response and write it to @out. */
449 int
450 wHTTP::readData (FILE *out)
451 {
452 const char *val;
453 char buf[1024+1];
454 int nlen = 0, nn = 0, n, eof=0;
455 int rc = 0;
456
457 if (this->fd == 0 || this->resp_headers == NULL)
458 return -1;
459
460 nlen = getContentLength ();
461 if (nlen == 0) {
462 if (!findHeader (resp_headers, "Connection", &val) ||
463 strnicmp (val, "close", 4))
464 return WPTERR_GENERAL;
465 }
466
467 val = getContentType ();
468 if (!val)
469 return WPTERR_GENERAL;
470 if (strnicmp (val, "text", 4)) { /* binary */
471 do {
472 n = recv (fd, buf, nlen > 1024? 1024 : nlen, 0);
473 if (n == -1)
474 return SOCKET_ERROR;
475 if (n == 0)
476 break;
477 nlen -= n;
478 fwrite (buf, 1, n, out);
479 } while (nlen > 0);
480 return 0;
481 }
482
483 do {
484 rc = readLine (buf, 1024, 1, &n, &eof);
485 if (rc)
486 return rc;
487 if (n > 0)
488 fwrite (buf, 1, n, out);
489 if (nlen > 0) {
490 nn += n;
491 if (nlen == nn)
492 break;
493 }
494 } while (eof == 0);
495
496 return 0;
497 }
498
499
500 /* Parse the HTTP response line. */
501 int
502 wHTTP::parseResponse (int *_statcode)
503 {
504 http_head_t n;
505 const char *tmp, *p;
506 char buf[300];
507 int code = 0, nn = 0;
508 int rc;
509
510 *_statcode = 0;
511 rc = readLine (buf, 299, 1, &nn, NULL);
512 if (rc)
513 return rc;
514
515 tmp = "HTTP/1.";
516 if (strlen (buf) < 8 || strncmp (buf, tmp, strlen (tmp)))
517 return WPTERR_GENERAL;
518 p = buf;
519 p += strlen (tmp)+1 + 1; /* skip HTTP/1.x and WS */
520 *_statcode = atoi (p);
521 if (tmp == 0)
522 return WPTERR_GENERAL;
523 p += 3 + 1; /* number + WS */
524
525 if (code == HTTP_STAT_400 ||
526 code == HTTP_STAT_403 ||
527 code == HTTP_STAT_404 ||
528 code == HTTP_STAT_405)
529 return WPTERR_GENERAL;
530
531 while (resp_headers) {
532 n = resp_headers->next;
533 free (resp_headers);
534 resp_headers = n;
535 }
536 resp_headers = NULL;
537 rc = parseHeaders (&resp_headers);
538 if (rc)
539 return rc;
540 return 0;
541 }
542
543
544 /* Destroy HTTP object. */
545 wHTTP::~wHTTP (void)
546 {
547
548 http_head_t h;
549
550 while (resp_headers) {
551 h = resp_headers->next;
552 free (resp_headers);
553 resp_headers = h;
554 }
555 while (req_headers) {
556 h = req_headers->next;
557 free (req_headers);
558 req_headers = h;
559 }
560 free_if_malloc (url);
561 free_if_malloc (host);
562 if (fd != 0) {
563 closesocket (fd);
564 fd = 0;
565 }
566 }
567
568
569 /* Read @buflen bytes from the http stream into the buffer @buf. */
570 int
571 wHTTP::read (void *buf, unsigned int buflen)
572 {
573 int n;
574
575 if (this->fd == 0 || this->resp_headers == NULL)
576 return -1;
577 if (method != HTTP_GET)
578 return -1;
579
580 if (nleft == -1)
581 nleft = getContentLength ();
582 if ((int)buflen > nleft)
583 buflen = nleft;
584 if (nleft == 0)
585 return -1;
586
587 n = recv (fd, (char*)buf, (int)buflen, 0);
588 if (n > 0) {
589 nleft -= n;
590 if (nleft < 0) nleft = 0;
591 }
592 return n;
593 }
594
595
596 /* Write the buffer @buf to the http stream. */
597 int
598 wHTTP::write (const void *buf, unsigned buflen)
599 {
600 if (this->fd == 0)
601 return -1;
602 if (method == HTTP_GET || method == HTTP_HEAD)
603 return -1;
604 return send (fd, (const char*)buf, (int)buflen, 0);
605 }
606
607
608 /* Return the winsock specific error code. */
609 int wHTTP::getErrorCode (void)
610 {
611 return error;
612 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26