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

Diff of /trunk/Src/wptHTTP.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 35 by twoaday, Wed Oct 12 10:04:26 2005 UTC revision 36 by werner, Thu Oct 27 15:25:13 2005 UTC
# Line 1  Line 1 
1  /* wptHTTP.c - Generic HTTP support  /* wptHTTP.c - Generic HTTP support
2   *      Copyright (C) 2004, 2005 Timo Schulz   *      Copyright (C) 2004, 2005 Timo Schulz
3   *   *
4   * This file is part of WinPT.   * This file is part of WinPT.
5   *   *
6   * WinPT is free software; you can redistribute it and/or   * WinPT is free software; you can redistribute it and/or
7   * modify it under the terms of the GNU General Public License   * modify it under the terms of the GNU General Public License
8   * as published by the Free Software Foundation; either version 2   * as published by the Free Software Foundation; either version 2
9   * of the License, or (at your option) any later version.   * of the License, or (at your option) any later version.
10   *     *  
11   * WinPT is distributed in the hope that it will be useful,   * WinPT is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   * General Public License for more details.   * General Public License for more details.
15   *   *
16   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
17   * along with WinPT; if not, write to the Free Software Foundation,   * along with WinPT; if not, write to the Free Software Foundation,
18   * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA   * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19   */   */
20  #include <stdio.h>  #ifdef HAVE_CONFIG_H
21  #include <stdlib.h>  #include <config.h>
22  #include <string.h>  #endif
23  #include <windows.h>  
24  #include <ctype.h>  #include <stdio.h>
25  #include <errno.h>  #include <stdio.h>
26    #include <stdlib.h>
27  #include "wptHTTP.h"  #include <string.h>
28  #include "wptTypes.h"  #include <windows.h>
29  #include "wptErrors.h"  #include <ctype.h>
30    #include <errno.h>
31    
32  static int parse_headers (int fd, http_head_t *r_head);  #include "wptHTTP.h"
33    #include "wptTypes.h"
34    #include "wptErrors.h"
35  static int  
36  http_head_new (http_head_t * head, const char * val)  
37  {  static int parse_headers (int fd, http_head_t *r_head);
38      http_head_t h;  
39        
40      h = calloc (1, sizeof *h + strlen (val) + 1);  static int
41      if (!h)  http_head_new (http_head_t * head, const char * val)
42          BUG (0);  {
43      strcpy (h->d, val);      http_head_t h;
44      *head = h;      
45      return 0;      h = calloc (1, sizeof *h + strlen (val) + 1);
46  }      if (!h)
47            BUG (0);
48        strcpy (h->d, val);
49  static void      *head = h;
50  http_head_free (http_head_t head)      return 0;
51  {  }
52      http_head_t h;  
53        
54      while (head) {  static void
55          h = head->next;  http_head_free (http_head_t head)
56          free (head);  {
57          head = h;      http_head_t h;
58      }      
59  }      while (head) {
60            h = head->next;
61            free (head);
62  static void          head = h;
63  http_head_add (http_head_t root, http_head_t node)      }
64  {  }
65      http_head_t n;  
66        
67      for (n = root; n->next; n=n->next)  static void
68          ;  http_head_add (http_head_t root, http_head_t node)
69      n->next = node;  {
70  }      http_head_t n;
71        
72        for (n = root; n->next; n=n->next)
73  static http_head_t          ;
74  http_head_find (http_head_t root, const char * name,      n->next = node;
75                  const char ** val)  }
76  {  
77      http_head_t n;  
78        static http_head_t
79      for (n = root; n; n = n->next) {  http_head_find (http_head_t root, const char * name,
80          if (strlen (n->d) >= strlen (name) &&                  const char ** val)
81              !strncmp (n->d, name, strlen (name))) {  {
82              *val = n->d + strlen (name);      http_head_t n;
83              return n;      
84          }      for (n = root; n; n = n->next) {
85      }          if (strlen (n->d) >= strlen (name) &&
86      return NULL;              !strncmp (n->d, name, strlen (name))) {
87  }              *val = n->d + strlen (name);
88                return n;
89            }
90  static int      }
91  http_connect (const char * host, int port, int * r_fd)      return NULL;
92  {  }
93      struct hostent * hp;  
94      struct sockaddr_in srv;  
95      unsigned long addr = 0;  static int
96      int i = 1;  http_connect (const char * host, int port, int * r_fd)
97      int fd;  {
98            struct hostent * hp;
99      *r_fd = 0;      struct sockaddr_in srv;
100      memset (&srv, 0, sizeof srv);      unsigned long addr = 0;
101      srv.sin_port = htons ((unsigned short)port);      int i = 1;
102      srv.sin_family = AF_INET;      int fd;
103            
104      if (isalpha (*host)) {      *r_fd = 0;
105          hp = gethostbyname (host);      memset (&srv, 0, sizeof srv);
106          if (hp == NULL)      srv.sin_port = htons ((unsigned short)port);
107              return WPTERR_WINSOCK_CONNECT;      srv.sin_family = AF_INET;
108          memcpy (&srv.sin_addr, hp->h_addr, hp->h_length);      
109      }      if (isalpha (*host)) {
110      else {          hp = gethostbyname (host);
111          addr = inet_addr (host);          if (hp == NULL)
112          if (addr == -1)              return WPTERR_WINSOCK_CONNECT;
113              return WPTERR_WINSOCK_CONNECT;          memcpy (&srv.sin_addr, hp->h_addr, hp->h_length);
114          memcpy (&srv.sin_addr, &addr, sizeof addr);      }
115      }      else {
116                        addr = inet_addr (host);
117      fd = socket (AF_INET, SOCK_STREAM, 0);          if (addr == -1)
118      if (fd < 0)              return WPTERR_WINSOCK_CONNECT;
119          return WPTERR_WINSOCK_SOCKET;          memcpy (&srv.sin_addr, &addr, sizeof addr);
120        }
121      if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&i, sizeof i)) {              
122          closesocket (fd);      fd = socket (AF_INET, SOCK_STREAM, 0);
123          return WPTERR_WINSOCK_SOCKET;      if (fd < 0)
124      }          return WPTERR_WINSOCK_SOCKET;
125        
126      if (connect (fd, (struct sockaddr *)&srv, sizeof srv)) {      if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&i, sizeof i)) {
127          closesocket (fd);          closesocket (fd);
128          return WPTERR_WINSOCK_CONNECT;          return WPTERR_WINSOCK_SOCKET;
129      }      }
130            
131      *r_fd = fd;      if (connect (fd, (struct sockaddr *)&srv, sizeof srv)) {
132      return 0;          closesocket (fd);
133  }          return WPTERR_WINSOCK_CONNECT;
134        }
135        
136  static int      *r_fd = fd;
137  http_close (int fd)      return 0;
138  {  }
139      closesocket (fd);  
140      return 0;  
141  }  static int
142    http_close (int fd)
143    {
144  static int      closesocket (fd);
145  http_data_avail (int fd)      return 0;
146  {  }
147      struct timeval tv;  
148      fd_set inp;  
149      int n;  static int
150    http_data_avail (int fd)
151      FD_ZERO (&inp);  {
152      FD_SET (fd, &inp);      struct timeval tv;
153      tv.tv_sec = 1;      fd_set inp;
154      tv.tv_usec = 0;      int n;
155    
156      n = select (fd+1, &inp, NULL, NULL, &tv);      FD_ZERO (&inp);
157      if (n && FD_ISSET (fd, &inp))      FD_SET (fd, &inp);
158          return n;      tv.tv_sec = 1;
159      return 0;      tv.tv_usec = 0;
160  }  
161        n = select (fd+1, &inp, NULL, NULL, &tv);
162        if (n && FD_ISSET (fd, &inp))
163  static int          return n;
164  http_read_line (int fd, char * buf, size_t nbuf,      return 0;
165                  int nonblock, int * nn, int * eof)  }
166  {  
167      char c;  
168      int n, i;  static int
169        http_read_line (int fd, char * buf, size_t nbuf,
170      if (nn)                  int nonblock, int * nn, int * eof)
171          *nn = 0;  {
172      if (eof)      char c;
173          *eof = 0;      int n, i;
174      i = 0;      
175      do {      if (nn)
176          if (nonblock == 1 && http_data_avail (fd) == 0) {          *nn = 0;
177              buf[i++] = '\0';      if (eof)
178              i = -1;          *eof = 0;
179              break;      i = 0;
180          }      do {
181          n = recv (fd, &c, 1, 0);          if (nonblock == 1 && http_data_avail (fd) == 0) {
182          if (n == -1)              buf[i++] = '\0';
183              break;              i = -1;
184          if (n == 0 || nbuf == 0 || c == '\n') {              break;
185              if (n == 0) {          }
186                  if (eof)          n = recv (fd, &c, 1, 0);
187                      *eof = 1;          if (n == -1)
188                  buf[i++] = '\0';              break;
189              }          if (n == 0 || nbuf == 0 || c == '\n') {
190              else {              if (n == 0) {
191                  buf[i++] = c;                  if (eof)
192                  buf[i] = '\0';                      *eof = 1;
193              }                  buf[i++] = '\0';
194              break;              }
195          }              else {
196          else {                  buf[i++] = c;
197              buf[i++] = c;                  buf[i] = '\0';
198              nbuf--;              }
199          }              break;
200      } while (n > 0 && i != -1);          }
201                else {
202      if (nn)              buf[i++] = c;
203          *nn = i;              nbuf--;
204      return 0;          }
205  }      } while (n > 0 && i != -1);
206        
207        if (nn)
208  static int          *nn = i;
209  http_send_req (int fd, const char * host, const char * url)      return 0;
210  {  }
211      char * p;  
212      int n;  
213        static int
214      if (*url == '/')  http_send_req (int fd, const char * host, const char * url)
215          url++;  {
216      if (url == NULL)      char * p;
217          url = "";      int n;
218      p = malloc (strlen (url) + strlen (host) + 64);      
219      if (p == NULL)      if (*url == '/')
220          BUG (0);          url++;
221      sprintf (p, "GET /%s HTTP/1.1\r\n"      if (url == NULL)
222                  "Host: %s\r\n"          url = "";
223                  "\r\n"      p = malloc (strlen (url) + strlen (host) + 64);
224                  "\r\n",      if (p == NULL)
225               url, host);          BUG (0);
226      n = send (fd, p, strlen (p), 0);      sprintf (p, "GET /%s HTTP/1.1\r\n"
227      free (p);                  "Host: %s\r\n"
228      if (n == -1)                  "\r\n"
229          return SOCKET_ERROR;                  "\r\n",
230      return 0;               url, host);
231  }      n = send (fd, p, strlen (p), 0);
232        free (p);
233        if (n == -1)
234  int          return SOCKET_ERROR;
235  http_send_request2 (const char * url, http_hd_t * r_hd)      return 0;
236  {  }
237      http_hd_t hd;  
238      char * host = NULL, * p;  
239      char tmpbuf[512];  int
240      int rc;  http_send_request2 (const char * url, http_hd_t * r_hd)
241    {
242      memset (tmpbuf, 0, 512);      http_hd_t hd;
243      strncpy (tmpbuf, url, 512);      char * host = NULL, * p;
244            char tmpbuf[512];
245      if (strlen (url) < 10 || strncmp (url, "http://", 7))      int rc;
246          return WPTERR_GENERAL;  
247      url += 7;      memset (tmpbuf, 0, 512);
248      p = strtok (tmpbuf+7, "/");      strncpy (tmpbuf, url, 512);
249      if (p == NULL)      
250          return WPTERR_GENERAL;      if (strlen (url) < 10 || strncmp (url, "http://", 7))
251      host = strdup (p);          return WPTERR_GENERAL;
252      if (host == NULL)      url += 7;
253          BUG (0);      p = strtok (tmpbuf+7, "/");
254      p = strchr (url, '/');      if (p == NULL)
255      if (p == NULL) {          return WPTERR_GENERAL;
256          free (host);      host = strdup (p);
257          return WPTERR_GENERAL;      if (host == NULL)
258      }          BUG (0);
259      rc = http_send_request (host, 80, p+1, &hd);      p = strchr (url, '/');
260      *r_hd = hd;      if (p == NULL) {
261      free (host);          free (host);
262      return rc;          return WPTERR_GENERAL;
263  }      }
264        rc = http_send_request (host, 80, p+1, &hd);
265        *r_hd = hd;
266  int      free (host);
267  http_send_request (const char * host, int port, const char * url,      return rc;
268                     http_hd_t * r_hd)  }
269  {  
270      http_hd_t hd;  
271      int rc;  int
272    http_send_request (const char * host, int port, const char * url,
273      http_hd_new (&hd);                     http_hd_t * r_hd)
274      rc = http_connect (host, port, &hd->fd);  {
275      if (!rc)      http_hd_t hd;
276          rc = http_send_req (hd->fd, host, url);      int rc;
277      if (r_hd)  
278          *r_hd = hd;      http_hd_new (&hd);
279      else      rc = http_connect (host, port, &hd->fd);
280          http_hd_free (hd);      if (!rc)
281      return rc;          rc = http_send_req (hd->fd, host, url);
282  }      if (r_hd)
283            *r_hd = hd;
284        else
285  int          http_hd_free (hd);
286  http_req_new (http_req_t * ctx)      return rc;
287  {  }
288      http_req_t c;  
289      c = calloc (1, sizeof * c);  
290      if (c == NULL)  int
291          BUG (0);  http_req_new (http_req_t * ctx)
292      *ctx = c;  {
293      return 0;      http_req_t c;
294  }      c = calloc (1, sizeof * c);
295        if (c == NULL)
296            BUG (0);
297  void      *ctx = c;
298  http_req_free (http_req_t ctx)      return 0;
299  {  }
300      if (!ctx)  
301          return;  
302      http_head_free (ctx->head);  void
303      if (ctx->url)  http_req_free (http_req_t ctx)
304          free (ctx->url);  {
305      free (ctx);      if (!ctx)
306  }          return;
307        http_head_free (ctx->head);
308        if (ctx->url)
309  static int          free (ctx->url);
310  parse_statline (const char * buf, int * code)      free (ctx);
311  {  }
312      int tmp = 0;  
313        
314      if (strlen (buf) < 8 ||  static int
315          (strncmp (buf, "HTTP/1.", 7)))  parse_statline (const char * buf, int * code)
316          return WPTERR_GENERAL;  {
317      buf += 8; /* skip HTTP/1.x */      int tmp = 0;
318      buf++;    /* white space */      
319      tmp = atoi (buf);      if (strlen (buf) < 8 ||
320      if (tmp == 0)          (strncmp (buf, "HTTP/1.", 7)))
321          return WPTERR_GENERAL;          return WPTERR_GENERAL;
322      *code = tmp;      buf += 8; /* skip HTTP/1.x */
323      buf += 3;      buf++;    /* white space */
324      buf++; /* whitespace */      tmp = atoi (buf);
325      return 0;      if (tmp == 0)
326  }          return WPTERR_GENERAL;
327        *code = tmp;
328        buf += 3;
329  static int      buf++; /* whitespace */
330  parse_headers (int fd, http_head_t * r_head)      return 0;
331  {  }
332      http_head_t h, head = NULL;  
333      char buf[300];  
334      int nn;  static int
335      int rc;  parse_headers (int fd, http_head_t * r_head)
336        {
337      do  {      http_head_t h, head = NULL;
338          rc = http_read_line (fd, buf, 299, 1, &nn, NULL);      char buf[300];
339          if (rc)      int nn;
340              return rc;      int rc;
341          if (nn == 2)      
342              break; /* reach empty line */      do  {
343          http_head_new (&h, buf);          rc = http_read_line (fd, buf, 299, 1, &nn, NULL);
344          if (head == NULL)          if (rc)
345              head = h;              return rc;
346          else          if (nn == 2)
347              http_head_add (head, h);              break; /* reach empty line */
348      } while (rc == 0);          http_head_new (&h, buf);
349      if (r_head)          if (head == NULL)
350          *r_head = head;              head = h;
351      else          else
352          http_head_free (head);              http_head_add (head, h);
353      return 0;      } while (rc == 0);
354  }      if (r_head)
355            *r_head = head;
356        else
357  static int          http_head_free (head);
358  read_binary (int fd, int nlen, FILE * out)      return 0;
359  {  }
360      char buf[1024+1];  
361      int n;  
362    static int
363      do  read_binary (int fd, int nlen, FILE * out)
364      {  {
365          n = recv (fd, buf, nlen > 1024? 1024 : nlen, 0);      char buf[1024+1];
366          if (n == -1)      int n;
367              return SOCKET_ERROR;  
368          if (n == 0)      do
369              break;      {
370          nlen -= n;          n = recv (fd, buf, nlen > 1024? 1024 : nlen, 0);
371          fwrite (buf, 1, n, out);          if (n == -1)
372      } while (nlen > 0);              return SOCKET_ERROR;
373      return 0;          if (n == 0)
374  }              break;
375            nlen -= n;
376            fwrite (buf, 1, n, out);
377  static int      } while (nlen > 0);
378  parse_data (int fd, http_head_t head, FILE * out)      return 0;
379  {  }
380      http_head_t h;  
381      const char * s = "Content-Length: ", * val;  
382      char buf[1024+1];  static int
383      int nlen = 0, nn = 0, n, eof=0;  parse_data (int fd, http_head_t head, FILE * out)
384      int rc;  {
385            http_head_t h;
386      h = http_head_find (head, s, &val);      const char * s = "Content-Length: ", * val;
387      if (h)      char buf[1024+1];
388          nlen = atoi (val);      int nlen = 0, nn = 0, n, eof=0;
389      else {      int rc;
390          h = http_head_find (head, "Connection: ", &val);      
391          if (h == NULL || strncmp (val, "close", 4))      h = http_head_find (head, s, &val);
392              return WPTERR_GENERAL;      if (h)
393      }          nlen = atoi (val);
394        else {
395      h = http_head_find (head, "Content-Type: ", &val);          h = http_head_find (head, "Connection: ", &val);
396      if (h == NULL)          if (h == NULL || strncmp (val, "close", 4))
397          return WPTERR_GENERAL;              return WPTERR_GENERAL;
398      if (strncmp (val, "text", 4))      }
399          return read_binary (fd, nlen, out);  
400            h = http_head_find (head, "Content-Type: ", &val);
401      do {      if (h == NULL)
402          rc = http_read_line (fd, buf, 1024, 1, &n, &eof);          return WPTERR_GENERAL;
403          if (rc)      if (strncmp (val, "text", 4))
404              return rc;          return read_binary (fd, nlen, out);
405          if (n > 0)      
406              fwrite (buf, 1, n, out);      do {
407          if (nlen > 0) {          rc = http_read_line (fd, buf, 1024, 1, &n, &eof);
408              nn += n;          if (rc)
409              if (nlen == nn)              return rc;
410                  break;          if (n > 0)
411          }              fwrite (buf, 1, n, out);
412      } while (eof == 0);          if (nlen > 0) {
413      return 0;              nn += n;
414  }              if (nlen == nn)
415                    break;
416            }
417  static int      } while (eof == 0);
418  check_status (int code, int * statcode)      return 0;
419  {  }
420      if (code != HTTP_STAT_200) {  
421          if (statcode)  
422              *statcode = code;  static int
423          if (code == HTTP_STAT_400 ||  check_status (int code, int * statcode)
424              code == HTTP_STAT_403 ||  {
425              code == HTTP_STAT_404 ||      if (code != HTTP_STAT_200) {
426              code == HTTP_STAT_405)          if (statcode)
427              return WPTERR_GENERAL;              *statcode = code;
428      }          if (code == HTTP_STAT_400 ||
429      return 0;              code == HTTP_STAT_403 ||
430  }              code == HTTP_STAT_404 ||
431                code == HTTP_STAT_405)
432                return WPTERR_GENERAL;
433  int      }
434  http_parse_response (http_hd_t hd, int * statcode)      return 0;
435  {  }
436      char buf[300];  
437      int rc;  
438      int code = 0, nn = 0;  int
439    http_parse_response (http_hd_t hd, int * statcode)
440      if (statcode)  {
441          *statcode = 0;      char buf[300];
442      rc = http_read_line (hd->fd, buf, 299, 1, &nn, NULL);      int rc;
443      if (rc)      int code = 0, nn = 0;
444          return rc;  
445      rc = parse_statline (buf, &code);      if (statcode)
446      if (rc)          *statcode = 0;
447          return rc;      rc = http_read_line (hd->fd, buf, 299, 1, &nn, NULL);
448      rc = check_status (code, statcode);      if (rc)
449      if (rc)          return rc;
450          return rc;      rc = parse_statline (buf, &code);
451      rc = parse_headers (hd->fd, &hd->head);      if (rc)
452      if (rc)          return rc;
453          return rc;      rc = check_status (code, statcode);
454      return 0;      if (rc)
455  }          return rc;
456        rc = parse_headers (hd->fd, &hd->head);
457        if (rc)
458  int          return rc;
459  http_parse_data (http_hd_t hd, FILE * out)      return 0;
460  {  }
461      int rc = 0;  
462      rc = parse_data (hd->fd, hd->head, out);  
463      http_close (hd->fd);      int
464      return rc;  http_parse_data (http_hd_t hd, FILE * out)
465  }  {
466        int rc = 0;
467        rc = parse_data (hd->fd, hd->head, out);
468  int      http_close (hd->fd);    
469  http_hd_new (http_hd_t * r_hd)      return rc;
470  {  }
471      http_hd_t hd;  
472    
473      if (!r_hd)  int
474          return -1;  http_hd_new (http_hd_t * r_hd)
475      hd = calloc (1, sizeof * hd);  {
476      if (hd == NULL)      http_hd_t hd;
477          abort ();  
478      *r_hd = hd;      if (!r_hd)
479      return 0;          return -1;
480  }      hd = calloc (1, sizeof * hd);
481        if (hd == NULL)
482            abort ();
483  void      *r_hd = hd;
484  http_hd_free (http_hd_t hd)      return 0;
485  {  }
486      if (!hd)  
487          return;  
488      http_head_free (hd->head);  void
489      http_close (hd->fd);  http_hd_free (http_hd_t hd)
490      free (hd);  {
491  }      if (!hd)
492            return;
493        http_head_free (hd->head);
494        http_close (hd->fd);
495        free (hd);
496    }

Legend:
Removed from v.35  
changed lines
  Added in v.36

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26