1 /*
2  * Copyright 2018-2021 Eduardo Chappa
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  */
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <time.h>
14 #include "c-client.h"	/* this includes http.h */
15 #include "flstring.h"
16 #include "netmsg.h"
17 
18 unsigned long http_debug;
19 
20 //char t[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&'*+-.^_`|~";
21 static char http_notok[] = "\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\40\42\50\51\54\57\72\73\74\75\76\77\100\133\134\135\173\175\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377";
22 static char http_noparam_val[] = "\1\2\3\4\5\6\7\10\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\42\134\177";
23 
24 #define HTP_NOVAL	0x001	/* the header accepts parameters without value */
25 
26 #define HTP_UNLIMITED	(-1)	/* parse and infinite list */
27 
28 #if 0
29 typedef struct http_val_param_s {
30   unsigned char *value;
31   PARAMETER *plist;
32 } HTTP_VAL_PARAM_S;
33 
34 typedef struct http_param_list_s {
35   HTTP_VAL_PARAM_S *vp;
36   struct http_param_list_s *next;
37 } HTTP_PARAM_LIST_S;
38 
39 typedef struct http_header_value_s {
40   unsigned char *data;
41   HTTP_PARAM_LIST_S *p;
42 } HTTP_HEADER_S;
43 
44 typedef struct http_header_data_s {
45   HTTP_HEADER_S *accept,		/* RFC 7231, Section 5.3.2 */
46 		*accept_charset,	/* RFC 7231, Section 5.3.3 */
47 		*accept_encoding,	/* RFC 7231, Section 5.3.4 */
48 		*accept_language,	/* RFC 7231, Section 5.3.5 */
49 		*accept_ranges,		/* RFC 7233, Section 2.3 */
50 		*age,			/* RFC 7234, Section 5.1 */
51 		*allow,			/* RFC 7231, Section 7.4.1 */
52 		*cache_control,		/* RFC 7234, Section 5.2 */
53 		*connection,		/* RFC 7230, Section 6.1 */
54 		*content_encoding,	/* RFC 7231, Section 3.1.2.2 */
55 		*content_disposition,	/* RFC 6266 */
56 		*content_language,	/* RFC 7231, Section 3.1.3.2 */
57 		*content_length,	/* RFC 7230, Section 3.3.2 */
58 		*content_location,	/* RFC 7231, Section 3.1.4.2 */
59 		*content_type,		/* RFC 7231, Section 3.1.1.5 */
60 		*date,			/* RFC 7231, Section 7.1.1.2 */
61 		*etag,			/* RFC 7232, Section 2.3 */
62 		*expect,		/* RFC 7231, Section 5.1.1 */
63 		*expires,		/* RFC 7234, Section 5.3 */
64 		*from,			/* RFC 7231, Section 5.5.1 */
65 		*host,			/* RFC 7230, Section 5.4 */
66 		*last_modified,		/* RFC 7232, Section 2.2 */
67 		*location,		/* RFC 7231, Section 7.1.2 */
68 		*max_forwards,		/* RFC 7231, Section 5.1.2  */
69 		*mime_version,		/* RFC 7231, Appendix A.1 */
70 		*pragma,		/* RFC 7234, Section 5.4 */
71 		*proxy_authenticate,	/* RFC 7235, Section 4.3 */
72 		*referer,		/* RFC 7231, Section 5.5.2 */
73 		*retry_after,		/* RFC 7231, Section 7.1.3 */
74 		*server,		/* RFC 7231, Section 7.4.2 */
75 		*te,			/* RFC 7230, Section 4.3 */
76 		*trailer,		/* RFC 7230, Section 4.4 */
77 		*transfer_encoding,	/* RFC 7230, Section 3.3.1 */
78 		*upgrade,		/* RFC 7230, Section 6.7 */
79 		*user_agent,		/* RFC 7231, Section 5.5.3 */
80 		*via,			/* RFC 7230, Section 5.7.1 */
81 		*vary,			/* RFC 7231, Section 7.1.4 */
82 		*warning,		/* RFC 7234, Section 5.5 */
83 		*www_authenticate;	/* RFC 7235, Section 4.1 */
84 } HTTP_HEADER_DATA_S;
85 #endif
86 
87 /* helper functions */
88 HTTP_STATUS_S *http_status_line_get(unsigned char *);
89 void http_status_line_free(HTTP_STATUS_S **);
90 void buffer_add(unsigned char **, unsigned char *);
91 unsigned char *hex_escape_url_part(unsigned char *, unsigned char *);
92 unsigned char *encode_url_body_part(unsigned char *, unsigned char *);
93 
94 /* HTTP function prototypes */
95 long http_reply (HTTPSTREAM *);
96 long http_fake (HTTPSTREAM *, unsigned char *);
97 
98 void http_skipows(unsigned char **);
99 void http_remove_trailing_ows(unsigned char *);
100 
101 int valid_dquote_text(unsigned char *);
102 #define valid_token_name(X)  (strpbrk((X), http_notok) ? 0 : 1)
103 #define valid_parameter_value(X) \
104 	((valid_token_name((X)) || valid_dquote_text((X))) ? 1 : 0)
105 
106 /* HTTP HEADER FUNCTIONS */
107 void http_add_header_data(HTTPSTREAM *, unsigned char *);
108 void http_add_data_to_header(HTTP_HEADER_S **, unsigned char *);
109 
110 HTTP_PARAM_LIST_S *http_parse_token_parameter(unsigned char *, int);
111 HTTP_PARAM_LIST_S *http_parse_token_list(unsigned char *, int);
112 PARAMETER *http_parse_parameter(unsigned char *, int);
113 
114 void http_parse_headers(HTTPSTREAM *);
115 
116 void *
http_parameters(long function,void * value)117 http_parameters (long function,void *value)
118 {
119    void *ret = NIL;
120    switch((int) function){
121 	case SET_HTTPDEBUG: http_debug = (long) value;
122 	case GET_HTTPDEBUG: ret = (void *) http_debug;
123 			    break;
124    }
125    return ret;
126 }
127 
128 
129 unsigned char *
http_response_from_reply(HTTPSTREAM * stream)130 http_response_from_reply(HTTPSTREAM *stream)
131 {
132   unsigned char *rv = NULL, *s;
133 
134   if(stream == NULL || stream->reply == NULL || stream->header == NULL)
135      return rv;
136 
137   s = strstr(stream->reply, "\r\n\r\n");
138   if(s != NULL) rv = s + 4;
139 
140   return s ? rv : NIL;
141 }
142 
143 void
http_parse_headers(HTTPSTREAM * stream)144 http_parse_headers(HTTPSTREAM *stream)
145 {
146   HTTP_HEADER_DATA_S *hd;
147   HTTP_HEADER_S *h;
148 
149   if(!stream || !stream->header) return;
150 
151   hd = stream->header;
152 
153   if(((h = hd->accept)) && h->data){		/* RFC 7231, Section 5.3.2 */
154      h->p = http_parse_token_parameter(h->data, HTP_NOVAL);
155      fs_give((void **) &h->data);
156   }
157 
158   if(((h = hd->accept_charset)) && h->data){	/* RFC 7231, Section 5.3.3 */
159      h->p = http_parse_token_parameter(h->data, 0);
160      fs_give((void **) &h->data);
161   }
162 
163   if(((h = hd->accept_encoding)) && h->data){	/* RFC 7231, Section 5.3.4 */
164      h->p = http_parse_token_parameter(h->data, 0);
165      fs_give((void **) &h->data);
166   }
167 
168   if(((h = hd->accept_language)) && h->data){	/* RFC 7231, Section 5.3.5 */
169      h->p = http_parse_token_parameter(h->data, 0);
170      fs_give((void **) &h->data);
171   }
172 
173   if(((h = hd->accept_ranges)) && h->data){	/* RFC 7233, Section 2.3 */
174      h->p = http_parse_token_parameter(h->data, 0);
175      fs_give((void **) &h->data);
176   }
177 
178   if(((h = hd->age)) && h->data){		/* RFC 7234, Section 5.1 */
179      h->p = http_parse_token_list(h->data, 1);
180      fs_give((void **) &h->data);
181   }
182 
183   if(((h = hd->allow)) && h->data){		/* RFC 7231, Section 7.4.1 */
184      h->p = http_parse_token_list(h->data, HTP_UNLIMITED);
185      fs_give((void **) &h->data);
186   }
187 
188   if(((h = hd->cache_control)) && h->data){	/* RFC 7234, Section 5.2 */
189      h->p = http_parse_token_parameter(h->data, HTP_NOVAL);
190      fs_give((void **) &h->data);
191   }
192 
193   if(((h = hd->connection)) && h->data){	/* RFC 7230, Section 6.1 */
194      h->p = http_parse_token_list(h->data, HTP_UNLIMITED);
195      fs_give((void **) &h->data);
196   }
197 
198   if(((h = hd->content_encoding)) && h->data){	/* RFC 7231, Section 3.1.2.2 */
199      h->p = http_parse_token_list(h->data, HTP_UNLIMITED);
200      fs_give((void **) &h->data);
201   }
202 
203   if(((h = hd->content_disposition)) && h->data){	/* RFC 6266 */
204      h->p = http_parse_token_parameter(h->data, HTP_NOVAL);
205      fs_give((void **) &h->data);
206   }
207 
208   if(((h = hd->content_language)) && h->data){	/* RFC 7231, Section 3.1.3.2 */
209      h->p = http_parse_token_list(h->data, HTP_UNLIMITED);
210      fs_give((void **) &h->data);
211   }
212 
213   if(((h = hd->content_length)) && h->data){	/* RFC 7230, Section 3.3.2 */
214      h->p = http_parse_token_list(h->data, HTP_UNLIMITED);
215      fs_give((void **) &h->data);
216   }
217 
218   if(((h = hd->content_location)) && h->data){	/* RFC 7231, Section 3.1.4.2 */
219      h->p = http_parse_token_list(h->data, 1);
220      fs_give((void **) &h->data);
221   }
222 
223   if(((h = hd->content_type)) && h->data){	/* RFC 7231, Section 3.1.1.5 */
224      h->p = http_parse_token_parameter(h->data, 0);
225      fs_give((void **) &h->data);
226   }
227 
228   if(((h = hd->date)) && h->data){	/* RFC 7231, Section 7.1.1.2 */
229      h->p = http_parse_token_list(h->data, 1);
230      fs_give((void **) &h->data);
231   }
232 
233   if(((h = hd->etag)) && h->data){	/* Rewrite this. RFC 7232, Section 2.3 */
234      h->p = http_parse_token_list(h->data, 1);
235      fs_give((void **) &h->data);
236   }
237 
238   if(((h = hd->expect)) && h->data){	/* Rewrite this. RFC 7231, Section 5.1.1 */
239      h->p = http_parse_token_list(h->data, 1);
240      fs_give((void **) &h->data);
241   }
242 
243   if(((h = hd->expires)) && h->data){	/* Rewrite this. RFC 7234, Section 5.3 */
244      h->p = http_parse_token_list(h->data, 1);
245      fs_give((void **) &h->data);
246   }
247 
248   if(((h = hd->from)) && h->data){	/* Rewrite this. RFC 7231, Section 5.5.1 */
249      h->p = http_parse_token_list(h->data, 1);
250      fs_give((void **) &h->data);
251   }
252 
253   if(((h = hd->host)) && h->data){	/* Rewrite this. RFC 7230, Section 5.4 */
254      h->p = http_parse_token_list(h->data, 1);
255      fs_give((void **) &h->data);
256   }
257 
258   if(((h = hd->last_modified)) && h->data){	/* Rewrite this. RFC 7232, Section 2.2 */
259      h->p = http_parse_token_list(h->data, 1);
260      fs_give((void **) &h->data);
261   }
262 
263   if(((h = hd->location)) && h->data){	/* Rewrite this. RFC 7231, Section 7.1.2 */
264      h->p = http_parse_token_list(h->data, 1);
265      fs_give((void **) &h->data);
266   }
267 
268   if(((h = hd->max_forwards)) && h->data){	/* RFC 7231, Section 5.1.2  */
269      h->p = http_parse_token_list(h->data, 1);
270      fs_give((void **) &h->data);
271   }
272 
273   if(((h = hd->mime_version)) && h->data){	/* Rewrite this. RFC 7231, Appendix A.1 */
274      h->p = http_parse_token_list(h->data, 1);
275      fs_give((void **) &h->data);
276   }
277 
278   if(((h = hd->pragma)) && h->data){		/* RFC 7234, Section 5.4 */
279      h->p = http_parse_token_parameter(h->data, HTP_NOVAL);
280      fs_give((void **) &h->data);
281   }
282 
283   if(((h = hd->proxy_authenticate)) && h->data){	/* Rewrite this. RFC 7235, Section 4.3 */
284      h->p = http_parse_token_parameter(h->data, 0);
285      fs_give((void **) &h->data);
286   }
287 
288   if(((h = hd->referer)) && h->data){	/* Rewrite this. RFC 7231, Section 5.5.2 */
289      h->p = http_parse_token_list(h->data, 1);
290      fs_give((void **) &h->data);
291   }
292 
293   if(((h = hd->retry_after)) && h->data){	/* Rewrite this. RFC 7231, Section 7.1.3 */
294      h->p = http_parse_token_list(h->data, 1);
295      fs_give((void **) &h->data);
296   }
297 
298   if(((h = hd->server)) && h->data){	/* Rewrite this. RFC 7231, Section 7.4.2 */
299      h->p = http_parse_token_list(h->data, 1);
300      fs_give((void **) &h->data);
301   }
302 
303   if(((h = hd->te)) && h->data){	/* Rewrite this. RFC 7230, Section 4.3 */
304      h->p = http_parse_token_parameter(h->data, 0);
305      fs_give((void **) &h->data);
306   }
307 
308   if(((h = hd->trailer)) && h->data){	/* RFC 7230, Section 4.4 */
309      h->p = http_parse_token_list(h->data, HTP_UNLIMITED);
310      fs_give((void **) &h->data);
311   }
312 
313   if(((h = hd->transfer_encoding)) && h->data){	/* Rewrite this. RFC 7230, Section 3.3.1 */
314      h->p = http_parse_token_parameter(h->data, 0);
315      fs_give((void **) &h->data);
316   }
317 
318   if(((h = hd->upgrade)) && h->data){	/* Rewrite this. RFC 7230, Section 6.7 */
319      h->p = http_parse_token_list(h->data, 1);
320      fs_give((void **) &h->data);
321   }
322 
323   if(((h = hd->user_agent)) && h->data){	/* Rewrite this. RFC 7231, Section 5.5.3 */
324      h->p = http_parse_token_list(h->data, HTP_UNLIMITED);
325      fs_give((void **) &h->data);
326   }
327 
328   if(((h = hd->via)) && h->data){	/* Rewrite this. RFC 7230, Section 5.7.1 */
329      h->p = http_parse_token_list(h->data, HTP_UNLIMITED);
330      fs_give((void **) &h->data);
331   }
332 
333   if(((h = hd->vary)) && h->data){	/* Rewrite this. RFC 7231, Section 7.1.4 */
334      h->p = http_parse_token_list(h->data, HTP_UNLIMITED);
335      fs_give((void **) &h->data);
336   }
337 
338   if(((h = hd->warning)) && h->data){	/* Rewrite this. RFC 7234, Section 5.5 */
339      h->p = http_parse_token_list(h->data, HTP_UNLIMITED);
340      fs_give((void **) &h->data);
341   }
342 
343   if(((h = hd->www_authenticate)) && h->data){	/* Rewrite this. RFC 7235, Section 4.1 */
344      h->p = http_parse_token_parameter(h->data, 0);
345      fs_give((void **) &h->data);
346   }
347 }
348 
349 
350 void
http_add_data_to_header(HTTP_HEADER_S ** headerp,unsigned char * data)351 http_add_data_to_header(HTTP_HEADER_S **headerp,  unsigned char *data)
352 {
353   HTTP_HEADER_S *h = *headerp;
354 
355   if(!h){
356       h = fs_get(sizeof(HTTP_HEADER_S));
357       memset((void *)h, 0, sizeof(HTTP_HEADER_S));
358   }
359 
360   if(h->data) buffer_add(&h->data, ", ");
361   buffer_add(&h->data, data);
362   *headerp = h;
363 }
364 
365 void
http_add_header_data(HTTPSTREAM * stream,unsigned char * hdata)366 http_add_header_data(HTTPSTREAM *stream, unsigned char *hdata)
367 {
368   unsigned char *hname, *h;
369   int found = 1;
370 
371   if(!stream || !hdata || !*hdata) return;
372 
373   if(!stream->header){
374      stream->header = fs_get(sizeof(HTTP_HEADER_DATA_S));
375      memset((void *) stream->header, 0, sizeof(HTTP_HEADER_DATA_S));
376   }
377 
378 
379   /* extract header name first */
380   if((h = strchr(hdata, ':'))){
381     *h = '\0';
382     hname = fs_get((h-hdata+2)*sizeof(char));
383     strncpy(hname, hdata, h-hdata);
384     hname[h-hdata] = '\0';
385     if(!valid_token_name(hname))
386        return;
387     hname[h-hdata] = ':';
388     hname[h-hdata+1] = '\0';
389     *h++ = ':';
390   }
391   else return;
392 
393   switch(*hname){
394      case 'A':
395      case 'a':  if(!compare_cstring(hname+1, "ccept:"))  /* RFC 7231, Section 5.3.2 */
396 		  http_add_data_to_header(&stream->header->accept,  h);
397 		else if(!compare_cstring(hname+1, "ccept-charset:")) /* RFC 7231, Section 5.3.3 */
398 		  http_add_data_to_header(&stream->header->accept_charset,  h);
399 		else if(!compare_cstring(hname+1, "ccept-encoding:")) /* RFC 7231, Section 5.3.4 */
400 		  http_add_data_to_header(&stream->header->accept_encoding,  h);
401 		else if(!compare_cstring(hname+1, "ccept-language:")) /* RFC 7231, Section 5.3.5 */
402 		  http_add_data_to_header(&stream->header->accept_language,  h);
403 		else if(!compare_cstring(hname+1, "ccept-ranges:")) /* RFC 7233, Section 2.3 */
404 		  http_add_data_to_header(&stream->header->accept_ranges,  h);
405 		else if(!compare_cstring(hname+1, "ge:")) /* RFC 7234, Section 5.1 */
406 		  http_add_data_to_header(&stream->header->age,  h);
407 		else if(!compare_cstring(hname+1, "llow:")) /* RFC 7231, Section 7.4.1 */
408 		  http_add_data_to_header(&stream->header->allow,  h);
409 		else found = 0;
410 		break;
411 
412      case 'C':
413      case 'c':  if(!compare_cstring(hname+1, "ache-control:"))	 /* RFC 7234, Section 5.2 */
414 		  http_add_data_to_header(&stream->header->cache_control,  h);
415 		else if(!compare_cstring(hname+1, "onnection:")) /* RFC 7230, Section 6.1 */
416 		  http_add_data_to_header(&stream->header->connection,  h);
417 		else if(!compare_cstring(hname+1, "ontent-disposition:")) /* RFC 6266 */
418 		  http_add_data_to_header(&stream->header->content_disposition,  h);
419 		else if(!compare_cstring(hname+1, "ontent-encoding:")) /* RFC 7231, Section 3.1.2.2 */
420 		  http_add_data_to_header(&stream->header->content_encoding,  h);
421 		else if(!compare_cstring(hname+1, "ontent-language:"))	/* RFC 7231, Section 3.1.3.2 */
422 /* rewrite this */  http_add_data_to_header(&stream->header->content_language,  h);
423 		else if(!compare_cstring(hname+1, "ontent-length:"))	/* RFC 7230, Section 3.3.2 */
424 		  http_add_data_to_header(&stream->header->content_length,  h);
425 		else if(!compare_cstring(hname+1, "ontent-location:"))	/* RFC 7231, Section 3.1.4.2 */
426 /* rewrite this */  http_add_data_to_header(&stream->header->content_location,  h);
427 		else if(!compare_cstring(hname+1, "ontent-type:"))	/* RFC 7231, Section 3.1.1.5 */
428 		  http_add_data_to_header(&stream->header->content_type,  h);
429 		else found = 0;
430 		break;
431 
432      case 'D':
433      case 'd':	if(!compare_cstring(hname+1, "ate:"))	/* RFC 7231, Section 7.1.1.2 */
434 /* revise this */  http_add_data_to_header(&stream->header->date,  h);
435 		else found = 0;
436 		break;
437 
438      case 'E':
439      case 'e':  if(!compare_cstring(hname+1, "tag:"))	/* RFC 7232, Section 2.3 */
440 /* rewrite this */  http_add_data_to_header(&stream->header->etag,  h);
441 		else if(!compare_cstring(hname+1, "xpect:"))	/* RFC 7231, Section 5.1.1 */
442 /* rewrite this */  http_add_data_to_header(&stream->header->expect,  h);
443 		else if(!compare_cstring(hname+1, "xpires:"))	/* RFC 7234, Section 5.3 */
444 /* rewrite this */  http_add_data_to_header(&stream->header->expires,  h);
445 		else found = 0;
446 		break;
447 
448      case 'F':
449      case 'f':	if(!compare_cstring(hname+1, "rom:"))	/* RFC 7231, Section 5.5.1 */
450 /* rewrite this */  http_add_data_to_header(&stream->header->from,  h);
451 		else found = 0;
452 		break;
453 
454      case 'H':
455      case 'h':	if(!compare_cstring(hname+1, "ost:"))	/* RFC 7230, Section 5.4 */
456 		  http_add_data_to_header(&stream->header->host,  h);
457 		else found = 0;
458 		break;
459 
460      case 'L':
461      case 'l':	if(!compare_cstring(hname+1, "ast-modified:"))	/* RFC 7232, Section 2.2 */
462 		  http_add_data_to_header(&stream->header->last_modified,  h);
463 		else if(!compare_cstring(hname+1, "ocation:"))	/* RFC 7231, Section 7.1.2 */
464 		  http_add_data_to_header(&stream->header->location,  h);
465 		else found = 0;
466 		break;
467 
468      case 'M':
469      case 'm':	if(!compare_cstring(hname+1, "ax-forwards:"))	/* RFC 7231, Section 5.1.2  */
470 		  http_add_data_to_header(&stream->header->max_forwards,  h);
471 		else if(!compare_cstring(hname+1, "ime-version:")) /* RFC 7231, Appendix A.1 */
472 		  http_add_data_to_header(&stream->header->mime_version,  h);
473 		else found = 0;
474 		break;
475 
476      case 'P':
477      case 'p':	if(!compare_cstring(hname+1, "ragma:")) /* RFC 7234, Section 5.4 */
478 		  http_add_data_to_header(&stream->header->pragma,  h);
479 		else if(!compare_cstring(hname+1, "roxy-authenticate:")) /* RFC 7235, Section 4.3 */
480 		  http_add_data_to_header(&stream->header->proxy_authenticate,  h);
481 		else found = 0;
482 		break;
483 
484      case 'R':
485      case 'r':	if(!compare_cstring(hname+1, "eferer:"))	/* RFC 7231, Section 5.5.2 */
486 		  http_add_data_to_header(&stream->header->referer,  h);
487 		else if(!compare_cstring(hname+1, "etry-after:")) /* RFC 7231, Section 7.1.3 */
488 		  http_add_data_to_header(&stream->header->retry_after,  h);
489 		else found = 0;
490 		break;
491 
492      case 'S':
493      case 's':	if(!compare_cstring(hname+1, "erver:")) /* RFC 7231, Section 7.4.2 */
494 		  http_add_data_to_header(&stream->header->server,  h);
495 		else found = 0;
496 		break;
497 
498      case 'T':
499      case 't':	if(!compare_cstring(hname+1, "e:"))	/* RFC 7230, Section 4.3 */
500 		  http_add_data_to_header(&stream->header->te,  h);
501 		else if(!compare_cstring(hname+1, "railer:")) /* RFC 7230, Section 4.4 */
502 		  http_add_data_to_header(&stream->header->trailer,  h);
503 		else if(!compare_cstring(hname+1, "ransfer-encoding:")) /* RFC 7230, Section 3.3.1 */
504 		  http_add_data_to_header(&stream->header->transfer_encoding,  h);
505 		else found = 0;
506 		break;
507 		break;
508 
509      case 'U':
510      case 'u':	if(!compare_cstring(hname+1, "pgrade:"))	/* RFC 7230, Section 6.7 */
511 		  http_add_data_to_header(&stream->header->upgrade,  h);
512 		else if(!compare_cstring(hname+1, "ser-agent:")) /* RFC 7231, Section 5.5.3 */
513 		  http_add_data_to_header(&stream->header->user_agent,  h);
514 		else found = 0;
515 		break;
516 
517      case 'V':
518      case 'v':	if(!compare_cstring(hname+1, "ia:"))	/* RFC 7230, Section 5.7.1 */
519 		  http_add_data_to_header(&stream->header->via,  h);
520 		else if(!compare_cstring(hname+1, "ary:")) /* RFC 7231, Section 7.1.4 */
521 		  http_add_data_to_header(&stream->header->vary,  h);
522 		else found = 0;
523 		break;
524 
525      case 'W':
526      case 'w':	if(!compare_cstring(hname+1, "arning:"))	/* RFC 7234, Section 5.5 */
527 		  http_add_data_to_header(&stream->header->warning,  h);
528 		else if(!compare_cstring(hname+1, "ww-authenticate:")) /* RFC 7235, Section 4.1 */
529 		  http_add_data_to_header(&stream->header->www_authenticate,  h);
530 		else found = 0;
531 		break;
532 
533       default:  break;
534   }
535 }
536 
537 
538 /* parse a list of tokens. If num is positive, parse at most
539  * num members in the list. Set num to HTP_UNLIMITED for a list
540  * without bounds
541  */
542 HTTP_PARAM_LIST_S *
http_parse_token_list(unsigned char * h,int num)543 http_parse_token_list(unsigned char *h, int num)
544 {
545   unsigned char *s = h, *t, c;
546   HTTP_PARAM_LIST_S *rv = NIL;
547 
548   if(!s || !*s || num == 0) return NIL;
549   http_skipows(&s);
550   if(!*s) return NIL;
551   for(t = s; *t != '\0' && *t != ','; t++);
552   c = *t; *t = '\0';
553   http_remove_trailing_ows(s);
554 
555   if(!valid_token_name(s))
556     return c == ',' ? http_parse_token_list(t+1, num) : NIL;
557 
558   if(num > 0) num--;	/* this one counts! */
559   rv = fs_get(sizeof(HTTP_PARAM_LIST_S));
560   memset((void *) rv, 0, sizeof(HTTP_PARAM_LIST_S));
561   rv->vp = fs_get(sizeof(HTTP_VAL_PARAM_S));
562   memset((void *) rv->vp, 0, sizeof(HTTP_VAL_PARAM_S));
563   rv->vp->value = cpystr(s);
564   *t = c;
565   if(c == ',')
566     rv->next = http_parse_token_list(t+1, num);
567 
568   return rv;
569 }
570 
571 
572 /*
573  * parse a list of tokens with optional parameters
574  * into a HEADER_DATA structure. Do not parse into
575  * it anything invalid.
576  */
577 HTTP_PARAM_LIST_S *
http_parse_token_parameter(unsigned char * h,int flag)578 http_parse_token_parameter(unsigned char *h, int flag)
579 {
580   unsigned char *s = h, *t, *u, c, d;
581   HTTP_PARAM_LIST_S *rv = NIL;
582 
583   /*
584    * Step 1:
585    * isolate first list element from list and remove
586    * leading and trailing white space.
587    */
588   if(!s) return NIL;
589   http_skipows(&s);
590   if(!*s) return NIL;
591   for(t = s; *t != '\0' && *t != ','; t++);
592   c = *t; *t = '\0';
593   http_remove_trailing_ows(s);
594 
595   /*
596    * Step 2:
597    * isolate token name from its parameters. Remove
598    * any trailing spaces. If not valid token, move
599    * to the next entry in the list.
600    */
601   for(u = s; *u != '\0' && *u != ';'; u++);
602   d = *u; *u = '\0';
603   http_remove_trailing_ows(s);
604   if(!valid_token_name(s))
605     return c == ',' ? http_parse_token_parameter(t+1, flag) : NIL;
606 
607   /*
608    * Step 3:
609    * If we make it this far, create a non-null reply
610    * and parse the token and parameters into a
611    * HTTP_HEADER_DATA_S structure
612    */
613   rv = fs_get(sizeof(HTTP_PARAM_LIST_S));
614   memset((void *) rv, 0, sizeof(HTTP_PARAM_LIST_S));
615   rv->vp = fs_get(sizeof(HTTP_VAL_PARAM_S));
616   memset((void *) rv->vp, 0, sizeof(HTTP_VAL_PARAM_S));
617   rv->vp->value = cpystr(s);
618   if(d == ';')
619     rv->vp->plist = http_parse_parameter(u+1, flag);
620   *u = d;
621   *t = c;
622   if(c == ',')
623     rv->next = http_parse_token_parameter(t+1, flag);
624 
625   return rv;
626 }
627 
628 int
valid_dquote_text(unsigned char * s)629 valid_dquote_text(unsigned char *s)
630 {
631   unsigned char *t;
632 
633   if(!s || *s != '\"') return 0;
634 
635   t = strchr(s+1, '\"');
636   return (t && !t[1]) ? 1 : 0;
637 }
638 
639 
640 void
http_skipows(unsigned char ** sp)641 http_skipows(unsigned char **sp)
642 {
643   unsigned char *s = *sp;
644   for(; *s == ' ' || *s == '\t'; s++);
645   *sp = s;
646 }
647 
648 void
http_remove_trailing_ows(unsigned char * s)649 http_remove_trailing_ows(unsigned char *s)
650 {
651   unsigned char *t;
652   for(t = s; strlen(t) > 0 ;)
653      if(t[strlen(t)-1] == ' ' || t[strlen(t)-1] == '\t')
654 	t[strlen(t)-1] = '\0';
655      else
656 	break;
657 }
658 
659 PARAMETER *
http_parse_parameter(unsigned char * s,int flag)660 http_parse_parameter(unsigned char *s, int flag)
661 {
662   PARAMETER *p;
663   unsigned char *t, *u, c;
664 
665   /* Step 1:
666    * separate the parameters into a list separated by ";"
667    */
668   if(!s || !*s) return NIL;
669   http_skipows(&s);
670   if(!*s) return NIL;
671   for(t = s; *t != '\0' && *t != ';'; t++);
672   c = *t; *t = '\0';
673 
674   /* Now we look for separation of attribute and value */
675   u = strchr(s, '=');
676 
677   if(u){
678     *u = '\0';
679     http_remove_trailing_ows(s); http_remove_trailing_ows(u+1);
680     if(!valid_token_name(s) || !valid_parameter_value(u+1))
681        return c == ';' ? http_parse_parameter(t+1, flag) : NIL;
682     p = mail_newbody_parameter();
683     p->attribute = cpystr(s);
684     p->value = cpystr(u+1);
685     p->next = c == ';' ? http_parse_parameter(t+1, flag) : NIL;
686     *u = '=';
687   }
688   else if(flag & HTP_NOVAL){
689     /* this is a parameter with attribute but no value. RFC 7231
690      * section 5.3.2 allows this.
691      */
692     http_remove_trailing_ows(s);
693     if(!valid_token_name(s))
694        return c == ';' ? http_parse_parameter(t+1, flag) : NIL;
695     p = mail_newbody_parameter();
696     p->attribute = cpystr(s);
697     p->next = c == ';' ? http_parse_parameter(t+1, flag) : NIL;
698   } else
699     p = c == ';' ? http_parse_parameter(t+1, flag) : NIL;
700 
701   return p;
702 }
703 
704 unsigned char *
http_get_param_url(unsigned char * url,HTTP_PARAM_S * param)705 http_get_param_url(unsigned char *url, HTTP_PARAM_S *param)
706 {
707   int i;
708   unsigned char *rv = NULL;
709   HTTP_PARAM_S enc_param;
710 
711   buffer_add(&rv, url);
712   for(i = 0; param[i].name != NULL; i++){
713     enc_param.name  = hex_escape_url_part(param[i].name, NULL);
714     enc_param.value = hex_escape_url_part(param[i].value, NULL);
715     buffer_add(&rv, i == 0 ? "?" : "&");
716     buffer_add(&rv, enc_param.name);
717     buffer_add(&rv, "=");
718     buffer_add(&rv, enc_param.value);
719     fs_give((void **) &enc_param.name);
720     fs_give((void **) &enc_param.value);
721   }
722 
723   return rv;
724 }
725 
726 HTTP_REQUEST_S *
http_request_get(void)727 http_request_get(void)
728 {
729   HTTP_REQUEST_S *rv = fs_get(sizeof(HTTP_REQUEST_S));
730   memset((void *) rv, 0, sizeof(HTTP_REQUEST_S));
731 
732   return rv;
733 }
734 
735 void
http_request_free(HTTP_REQUEST_S ** hr)736 http_request_free(HTTP_REQUEST_S **hr)
737 {
738   if(!hr) return;
739 
740   if((*hr)->request) fs_give((void **) &(*hr)->request);
741   if((*hr)->header) fs_give((void **) &(*hr)->header);
742   if((*hr)->body) fs_give((void **) &(*hr)->body);
743   fs_give((void **) hr);
744 }
745 
746 unsigned char *
http_request_line(unsigned char * method,unsigned char * target,unsigned char * version)747 http_request_line(unsigned char *method, unsigned char *target, unsigned char *version)
748 {
749   int len = strlen(method) + strlen(target) + strlen(version) + 2 + 1;
750   unsigned char *line = fs_get(len*sizeof(char));
751 
752   sprintf(line, "%s %s %s", method, target, version);
753   return line;
754 }
755 
756 void
http_add_header(HTTP_REQUEST_S ** reqp,unsigned char * name,unsigned char * value)757 http_add_header(HTTP_REQUEST_S **reqp, unsigned char *name, unsigned char *value)
758 {
759   int len, hlen;
760 
761   if(!reqp) return;
762 
763   if(!*reqp) *reqp = http_request_get();
764 
765   len  = strlen(name) + 2 + strlen(value) + 2 + 1;
766   hlen = (*reqp)->header ? strlen((*reqp)->header) : 0;
767   len += hlen;
768   fs_resize((void **) &(*reqp)->header, len*sizeof(char));
769   sprintf((*reqp)->header + hlen, "%s: %s\015\012", name, value);
770 }
771 
772 void
buffer_add(unsigned char ** bufp,unsigned char * text)773 buffer_add(unsigned char **bufp, unsigned char *text)
774 {
775   int len;
776 
777   if(!bufp || !text || !*text) return;
778 
779   len = *bufp ? strlen(*bufp) : 0;
780   fs_resize((void **) bufp, (len + strlen(text) + 1)*sizeof(char));
781   (*bufp)[len] = '\0';
782   strcat(*bufp, text);
783 }
784 
785 void
http_add_body(HTTP_REQUEST_S ** reqp,unsigned char * text)786 http_add_body(HTTP_REQUEST_S **reqp, unsigned char *text)
787 {
788   if(!reqp) return;
789 
790   if(!*reqp) *reqp = http_request_get();
791 
792   buffer_add(&(*reqp)->body, text);
793 }
794 
795 
796 /* NULL terminated list of HTTP_PARAM_S objects.
797  * If caller needs "x" parameters, call this function
798  * with argument "x+1".
799  */
800 HTTP_PARAM_S *
http_param_get(int len)801 http_param_get(int len)
802 {
803   HTTP_PARAM_S *http_params;
804 
805   http_params = fs_get(len*sizeof(HTTP_PARAM_S));
806   memset((void *) http_params, 0, len*sizeof(HTTP_PARAM_S));
807   return http_params;
808 }
809 
810 void
http_param_free(HTTP_PARAM_S ** param)811 http_param_free(HTTP_PARAM_S **param)
812 {
813   int i;
814 
815   if(param == NULL) return;
816 
817   for(i = 0; (*param)[i].name != NULL; i++)
818     fs_give((void **) &(*param)[i].name);
819 
820   for(i = 0; (*param)[i].value != NULL; i++)
821     fs_give((void **) &(*param)[i].value);
822 
823   fs_give((void **) param);
824 }
825 
826 
827 /* This encodes for a GET request */
828 unsigned char *
hex_escape_url_part(unsigned char * text,unsigned char * addsafe)829 hex_escape_url_part(unsigned char *text, unsigned char *addsafe)
830 {
831   char *safechars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.-";
832   unsigned char *s = fs_get((3*strlen(text) + 1)*sizeof(char)), *t;
833 
834   *s = '\0';
835   for(t = text; *t != '\0'; t++)
836      if(strchr(safechars, *t) != NULL
837 	|| (addsafe != NULL && strchr(addsafe, *t) != NULL))
838 	sprintf(s + strlen(s), "%c", *t);
839      else
840 	sprintf(s + strlen(s), "%%%X", *t);
841   fs_resize((void **) &s, (strlen(s)+1)*sizeof(char));
842   return s;
843 }
844 
845 /* this encodes for a POST request */
846 unsigned char *
encode_url_body_part(unsigned char * text,unsigned char * addsafe)847 encode_url_body_part(unsigned char *text, unsigned char *addsafe)
848 {
849   char *safechars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.-";
850   unsigned char *s = fs_get((3*strlen(text) + 1)*sizeof(char)), *t;
851 
852   *s = '\0';
853   for(t = text; *t != '\0'; t++)
854      if(*t == ' ')      /* ASCII 32 is never safe, must always be encoded */
855         sprintf(s + strlen(s), "%c", '+');
856      else if(strchr(safechars, *t) != NULL
857         || (addsafe != NULL && strchr(addsafe, *t) != NULL))
858         sprintf(s + strlen(s), "%c", *t);
859      else
860         sprintf(s + strlen(s), "%%%X", *t);
861   fs_resize((void **) &s, (strlen(s)+1)*sizeof(char));
862   return s;
863 }
864 
865 int
http_valid_net_parse(unsigned char * url,NETMBX * mb)866 http_valid_net_parse (unsigned char *url, NETMBX *mb)
867 {
868    int i, len;
869    unsigned char *s;
870    char *p;
871 
872    if((url == NIL)
873       || (url[0] != 'h' && url[0] != 'H')
874       || (url[1] == 't' && url[1] == 'T')
875       || (url[2] == 't' && url[2] == 'T')
876       || (url[3] == 'p' && url[3] == 'P'))
877      return 0;
878 
879    if(url[i = 4] == 's' || url[i] == 'S')
880        mb->sslflag = mb->notlsflag = T;
881    else i = 3;
882 
883    if(url[++i] != ':' || url[++i] != '/' || url[++i] != '/')
884      return 0;
885 
886    strcpy(mb->service, "http");
887    s = strchr(url+i+1, '/');
888    len = s ? s - url - i - 1 : strlen(url+i+1);
889    strncpy(mb->orighost, url+i+1, len);
890    mb->orighost[len] = '\0';
891    if((p = strchr(mb->orighost, ':')) != NULL){
892       *p++ = '\0';
893       mb->port = strtoul(p, &p, 10);
894       if(mb->port == 0L || *p != '\0')
895 	return NIL;
896    }
897    strcpy(mb->host, mb->orighost);
898    return T;
899 }
900 
901 HTTPSTREAM *
http_open(unsigned char * url)902 http_open (unsigned char *url)
903 {
904   HTTPSTREAM *stream;
905   NETMBX mb;
906   unsigned char *s;
907 
908   memset((void *) &mb, 0, sizeof(NETMBX));
909   if(http_valid_net_parse (url,&mb) == 0)
910     return NIL;
911 
912   stream = fs_get(sizeof(HTTPSTREAM));
913   memset((void *) stream, 0, sizeof(HTTPSTREAM));
914 
915   s = strchr((char *) url + 7 + (mb.trysslflag ? 1 : 0) + 1, '/'); /* 7 = strlen("http://") + 1 */
916   stream->url     = cpystr(url);
917   stream->urlhost = cpystr(mb.orighost);
918   stream->urltail = cpystr(s ? (char *) s : "/");
919   stream->netstream = net_open (&mb, NIL, mb.port ? mb.port : HTTPTCPPORT,
920 		 (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL),
921 		 "https", mb.port ? mb.port : HTTPSSLPORT);
922   stream->debug = http_debug;
923   if(!stream->netstream){
924       http_close(stream);
925       stream = NIL;
926   }
927   return stream;
928 }
929 
930 unsigned char *
http_post_param(HTTPSTREAM * stream,HTTP_PARAM_S * param)931 http_post_param(HTTPSTREAM *stream, HTTP_PARAM_S *param)
932 {
933   HTTP_PARAM_S enc_param;
934   HTTP_REQUEST_S *http_request;
935   unsigned char *response = NULL;
936   int i;
937 
938   if(stream == NULL || param == NULL ) return response;
939 
940   http_request = http_request_get();
941   http_request->request = http_request_line("POST", stream->urltail, HTTP_1_1_VERSION);
942   http_add_header(&http_request, "Host", stream->urlhost);
943   http_add_header(&http_request, "Content-Type", HTTP_MIME_URLENCODED);
944 
945   for(i = 0; param[i].name != NULL; i++){
946     enc_param.name  = encode_url_body_part(param[i].name, NULL);
947     enc_param.value = encode_url_body_part(param[i].value, NULL);
948     if(i > 0)
949        http_add_body(&http_request, "&");
950     http_add_body(&http_request, enc_param.name);
951     http_add_body(&http_request, "=");
952     http_add_body(&http_request, enc_param.value);
953     fs_give((void **) &enc_param.name);
954     fs_give((void **) &enc_param.value);
955   }
956 
957   if(http_send(stream, http_request)){
958      unsigned char *s = http_response_from_reply(stream);
959      response = cpystr(s ? (char *) s : "");
960   }
961 
962   http_request_free(&http_request);
963 
964   return response;
965 }
966 
967 unsigned char *
http_get(HTTPSTREAM * stream,HTTP_PARAM_S ** h)968 http_get(HTTPSTREAM *stream, HTTP_PARAM_S **h)
969 {
970   HTTP_REQUEST_S *http_request;
971   unsigned char *response = NIL;
972   int i;
973 
974   if(!stream) return response;
975 
976   http_request = http_request_get();
977   http_request->request = http_request_line("GET", stream->urltail, HTTP_1_1_VERSION);
978   http_add_header(&http_request, "Host", stream->urlhost);
979   for(i = 0; h && h[i]->name && h[i]->value; i++)
980      http_add_header(&http_request, h[i]->name, h[i]->value);
981 
982   if(http_send(stream, http_request)){
983      unsigned char *s = http_response_from_reply(stream);
984      response = cpystr(s ? (char *) s : "");
985   }
986 
987   http_request_free(&http_request);
988 
989   return response;
990 }
991 
992 void
http_close(HTTPSTREAM * stream)993 http_close (HTTPSTREAM *stream)
994 {
995   if(stream){
996      if (stream->netstream) net_close (stream->netstream);
997      stream->netstream = NIL;
998      if (stream->url)	   fs_give ((void **) &stream->url);
999      if (stream->urlhost)  fs_give ((void **) &stream->urlhost);
1000      if (stream->urltail)  fs_give ((void **) &stream->urltail);
1001      if (stream->response) fs_give ((void **) &stream->response);
1002      if (stream->reply)    fs_give ((void **) &stream->reply);
1003      fs_give((void **) &stream);
1004   }
1005 }
1006 
1007 long
http_send(HTTPSTREAM * stream,HTTP_REQUEST_S * req)1008 http_send (HTTPSTREAM *stream, HTTP_REQUEST_S *req)
1009 {
1010   long ret;
1011   unsigned char *s = NULL;
1012 
1013   if (!stream->netstream)
1014     ret = http_fake (stream,"http connection lost");
1015   else {
1016     if(req->body){
1017       char length[20];
1018 
1019       sprintf(length, "%lu", strlen(req->body));
1020       http_add_header(&req, "Content-Length", length);
1021     }
1022 
1023     buffer_add(&s, req->request); buffer_add(&s, "\015\012");
1024     buffer_add(&s, req->header); buffer_add(&s, "\015\012");
1025     buffer_add(&s, req->body); buffer_add(&s, "\015\012");
1026 
1027     if(stream->debug) mm_log(s, HTTPDEBUG);
1028 
1029     ret = net_soutr (stream->netstream,s)
1030 	  ? http_reply (stream)
1031 	  : http_fake (stream,"http connection broken in command");
1032     fs_give ((void **) &s);
1033   }
1034   return ret;
1035 }
1036 
1037 HTTP_STATUS_S *
http_status_line_get(unsigned char * status_line)1038 http_status_line_get(unsigned char *status_line)
1039 {
1040    HTTP_STATUS_S *rv = NULL;
1041    char *version, *s;
1042    int code;
1043 
1044    if(!status_line) return NIL;
1045 
1046    if((s = strchr(status_line, ' ')) != NIL){
1047       *s = '\0';
1048       version = cpystr(status_line);
1049       *s++ = ' ';
1050       code = strtoul(s, &s, 10);
1051       if(s && *s == ' ' && code >= 100 && code < 600){
1052         rv = fs_get(sizeof(HTTP_STATUS_S));
1053 	rv->version = version;
1054 	rv->code = code;
1055 	rv->text = cpystr(++s);
1056       }
1057       else
1058 	fs_give((void **) &version);
1059    }
1060    return rv;
1061 }
1062 
1063 void
http_status_line_free(HTTP_STATUS_S ** status)1064 http_status_line_free(HTTP_STATUS_S **status)
1065 {
1066   if(status == NULL) return;
1067 
1068   if((*status)->version) fs_give((void **) &(*status)->version);
1069   if((*status)->text) fs_give((void **) &(*status)->text);
1070   fs_give((void **) status);
1071 }
1072 
1073 
1074 long
http_reply(HTTPSTREAM * stream)1075 http_reply (HTTPSTREAM *stream)
1076 {
1077   int in_header = 1;
1078   unsigned long size;
1079 
1080   if (stream->response) fs_give ((void **) &stream->response);
1081   stream->response = (unsigned char *) net_getline(stream->netstream);
1082 
1083   if(stream->debug) mm_log(stream->response ? stream->response : (unsigned char *) "<NIL RESPONSE>", HTTPDEBUG);
1084 
1085   if(stream->response){
1086      buffer_add(&stream->reply, stream->response);
1087      buffer_add(&stream->reply, "\015\012");
1088   }
1089 
1090   if(stream->status) http_status_line_free(&stream->status);
1091   stream->status = http_status_line_get(stream->response);
1092 
1093   if(!stream->status){
1094     http_fake(stream, "Invalid status line received. Closing connection");
1095     return NIL;
1096   }
1097 
1098   while (in_header > 0){
1099     if (stream->response) fs_give ((void **) &stream->response);
1100     stream->response = (unsigned char *) net_getline (stream->netstream);
1101     if(stream->response){
1102        buffer_add(&stream->reply, stream->response);
1103        http_add_header_data(stream, stream->response);
1104        if(stream->debug) mm_log(stream->response, HTTPDEBUG);
1105     }
1106      buffer_add(&stream->reply, "\015\012");
1107 //    save_header(stream->headers, stream->response);
1108     if(!stream->response  || *stream->response == '\0')
1109 	in_header--;
1110   }
1111 
1112   http_parse_headers(stream);
1113   if(stream->header->content_length){
1114      size = atol(stream->header->content_length->p->vp->value);
1115      if (stream->response) fs_give ((void **) &stream->response);
1116      stream->response = (unsigned char *) net_getsize (stream->netstream, size);
1117      if(stream->response){
1118 	buffer_add(&stream->reply, stream->response);
1119 	if(stream->debug) mm_log(stream->response, HTTPDEBUG);
1120      }
1121   }
1122   else if (stream->header->transfer_encoding){
1123      HTTP_PARAM_LIST_S *p = stream->header->transfer_encoding->p;
1124      for(; p ; p = p->next){
1125 	if(!compare_cstring(p->vp->value, "chunked"))
1126 	   break;
1127      }
1128      if(p && p->vp->value){	/* chunked transfer */
1129 	unsigned char *s = NIL;
1130 	do {
1131 	  if (s) fs_give ((void **) &s);
1132 	  size = 0L;
1133 	  if((s = (unsigned char *) net_getline (stream->netstream)) != NIL){
1134 	     if(stream->debug) mm_log(s, HTTPDEBUG);
1135 	     size = strtol(s, NIL, 16);
1136 	     fs_give ((void **) &stream->response);
1137 	     if(size > 0){
1138 	       stream->response = (unsigned char *) net_getsize (stream->netstream, size);
1139 	       buffer_add(&stream->reply, stream->response);
1140 	       if(stream->debug) mm_log(stream->response, HTTPDEBUG);
1141 	     }
1142 	  }
1143 	} while (stream && stream->netstream && s && (size > 0 || !*s ));
1144      }
1145   }
1146 
1147   if(!stream->netstream)
1148     http_fake(stream, "Connection to HTTP server closed");
1149   return stream->netstream ? T : NIL;
1150 }
1151 
1152 long
http_fake(HTTPSTREAM * stream,unsigned char * text)1153 http_fake (HTTPSTREAM *stream, unsigned char *text)
1154 {
1155   if (stream->netstream) net_close (stream->netstream);
1156   stream->netstream = NIL;
1157   if (stream->response) fs_give ((void **) &stream->response);
1158   /* add *text to the log, to pass this to the client */
1159   return NIL;
1160 }
1161