1 /*
2  * Some code in this file is derived from the public domain code in
3  *              WWW/Library/Implementation/HTTP.c distributed with lynx-2.2,
4  *              whose original author is Tim Berners-lee <timbl@info.cern.ch>.
5  *
6  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
7  *
8  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
9  *
10  * This file may be distributed under the terms of the Q Public License
11  * as defined by Trolltech AS of Norway and appearing in the file
12  * LICENSE.QPL included in the packaging of this file.
13  *
14  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
15  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
17  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
18  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
19  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
20  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  *
22  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/http.c,v 1.11 2011/05/16 16:21:57 william Exp $
23  */
24 
25 #define _INCLUDE_FROM_HTTP_C_
26 
27 #include "tgifdefs.h"
28 
29 #include "dialog.e"
30 #include "drawing.e"
31 #include "file.e"
32 #include "http.e"
33 #include "mainloop.e"
34 #include "msg.e"
35 #include "remote.e"
36 #include "setup.e"
37 #include "stream.e"
38 #include "strtbl.e"
39 #include "tcp.e"
40 #include "util.e"
41 #include "version.e"
42 
43 int debugHttp=0;
44 int gnHttpKeepAlive=FALSE;
45 char *gpszFakedReferer=NULL;
46 
47 typedef struct TgifHttpLineInfo {
48    char *name;
49    char *value;
50    struct TgifHttpLineInfo *next;
51 } *TgifHttpLinePtr;
52 
53 typedef struct TgifHttpHeaderInfo {
54    char *version;
55    int resp_code;
56    char *resp_status;
57    char *last_modified;
58    char *server;
59    char *connection;
60    char *location;
61    char *www_authenticate;
62    char *content_encoding;
63    char *content_type;
64    long content_length;
65    struct TgifHttpLineInfo *misc;
66 } *TgifHttpHeaderPtr;
67 
68 typedef struct AuthInfo {
69    char *host;
70    int port;
71    char *scheme; /* e.g., Basic */
72    char *realm; /* e.g., WallyWorld */
73    char *authorization; /* base64 encoded */
74    struct AuthInfo *next, *prev;
75 } *AuthInfoPtr;
76 
77 static struct AuthInfo *topAuthInfo=NULL, *botAuthInfo=NULL;
78 static struct AuthInfo curAuthorization;
79 
80 static struct TgifHttpHeaderInfo tgifHttpHeaderInfo;
81 
82 static char SZ_HTTP_VERSION[]="HTTP/1.0";
83 static char SZ_USER_AGENT[128];
84 static char SZ_USER_NAME[128];
85 
86 typedef struct tagRefererInfo {
87    char *referer;
88    struct tagRefererInfo *next;
89 } RefererInfo;
90 
91 static RefererInfo *topReferer=NULL;
92 
HttpFreeBuf(buf)93 void HttpFreeBuf(buf)
94    char *buf;
95 {
96    free(buf);
97 }
98 
HttpDebug(val)99 void HttpDebug(val)
100    int val;
101 {
102    debugHttp = val;
103 }
104 
105 static
CleanUpAuthInfo()106 void CleanUpAuthInfo()
107 {
108    struct AuthInfo *next_pai;
109 
110    for ( ; topAuthInfo != NULL; topAuthInfo=next_pai) {
111       next_pai = topAuthInfo->next;
112       if (topAuthInfo->host != NULL) free(topAuthInfo->host);
113       if (topAuthInfo->scheme != NULL) free(topAuthInfo->scheme);
114       if (topAuthInfo->realm != NULL) free(topAuthInfo->realm);
115       if (topAuthInfo->authorization != NULL) free(topAuthInfo->authorization);
116       free(topAuthInfo);
117    }
118    botAuthInfo = NULL;
119 }
120 
121 /* do not translate -- program constants */
122 static char gszEncode[] =
123       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
124 static int gnDecode[] = {
125    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
126    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
127    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
128    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
129    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
130    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
131    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
132    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
133 };
134 
DoBase64Encode(buf_in,buf_len,return_buf_in)135 void DoBase64Encode(buf_in, buf_len, return_buf_in)
136    char *buf_in, *return_buf_in;
137    int buf_len;
138 {
139    unsigned char *buf=(unsigned char *)buf_in;
140    unsigned char *return_buf=(unsigned char *)return_buf_in;
141 
142    while (buf_len > 0) {
143       switch (buf_len) {
144       case 1:
145          return_buf[0] = gszEncode[(int)((buf[0]>>2) & 0x3f)];
146          return_buf[1] = gszEncode[(int)((buf[0]<<4) & 0x3f)];
147          return_buf[2] = '=';
148          return_buf[3] = '=';
149          return_buf[4] = '\0';
150          buf++;
151          buf_len--;
152          return;
153       case 2:
154          return_buf[0] = gszEncode[(int)((buf[0]>>2) & 0x3f)];
155          return_buf[1] = gszEncode[(int)(((buf[0]<<4) | (buf[1]>>4)) & 0x3f)];
156          return_buf[2] = gszEncode[(int)((buf[1]<<2) & 0x3f)];
157          return_buf[3] = '=';
158          return_buf[4] = '\0';
159          buf += 2;
160          buf_len -= 2;
161          return;
162       default: /* convert 3 bytes */
163          return_buf[0] = gszEncode[(int)((buf[0]>>2) & 0x3f)];
164          return_buf[1] = gszEncode[(int)(((buf[0]<<4) | (buf[1]>>4)) & 0x3f)];
165          return_buf[2] = gszEncode[(int)(((buf[1]<<2) | (buf[2]>>6)) & 0x3f)];
166          return_buf[3] = gszEncode[(int)(buf[2] & 0x3f)];
167          return_buf[4] = '\0';
168          buf += 3;
169          buf_len -= 3;
170          break;
171       }
172       return_buf += 4;
173    }
174 }
175 
Base64Encode(buf)176 char *Base64Encode(buf)
177    char *buf;
178 {
179    int len=strlen(buf), new_len;
180    char *return_buf;
181 
182    new_len = (int)(len/3);
183    new_len += 3;
184    new_len <<= 2;
185    return_buf = (char*)malloc(new_len*sizeof(char));
186    if (return_buf == NULL) return NULL;
187    DoBase64Encode(buf, len, return_buf);
188    return return_buf;
189 }
190 
191 static
Convert(buf4,count,buf3)192 int Convert(buf4, count, buf3)
193    int *buf4, count;
194    char *buf3;
195 {
196    switch (count) {
197    case 2:
198       buf3[0] = ((buf4[0]<<2) & 0xfc) | ((buf4[1]>>4) & 0x03);
199       buf3[1] = '\0';
200       return 1;
201    case 3:
202       buf3[0] = ((buf4[0]<<2) & 0xfc) | ((buf4[1]>>4) & 0x03);
203       buf3[1] = ((buf4[1]<<4) & 0xf0) | ((buf4[2]>>2) & 0x0f);
204       buf3[2] = '\0';
205       return 2;
206    case 4:
207       buf3[0] = (char)(((buf4[0]<<2) & 0xfc) | ((buf4[1]>>4) & 0x03));
208       buf3[1] = (char)(((buf4[1]<<4) & 0xf0) | ((buf4[2]>>2) & 0x0f));
209       buf3[2] = (char)(((buf4[2]<<6) & 0xc0) | (buf4[3] & 0x3f));
210       buf3[3] = '\0';
211       return 3;
212    default:
213 #ifdef _TGIF_DBG /* debug, do not translate */
214       Error("Convert()", "Bad count passed to Convert().");
215 #endif /* _TGIF_DBG */
216       break;
217    }
218    return 0;
219 }
220 
DoBase64Decode(buf,buf_sz,return_buf)221 int DoBase64Decode(buf, buf_sz, return_buf)
222    char *buf, *return_buf;
223    int buf_sz;
224 {
225    int i=0, j=0, bytes_decoded=0, intbuf[5];
226 
227    intbuf[4] = (-1);
228    for (i=0, j=0; i < buf_sz; i++) {
229       intbuf[j++] = gnDecode[(int)buf[i]];
230       if (j == 4) {
231          char out_buf[4];
232          int k=0, bytes=0;
233 
234          if (intbuf[3] == (-1)) {
235             if (intbuf[2] == (-1)) {
236                bytes = Convert(intbuf, 2, out_buf);
237             } else {
238                bytes = Convert(intbuf, 3, out_buf);
239             }
240          } else {
241             bytes = Convert(intbuf, 4, out_buf);
242          }
243          for (k=0; k < bytes; k++) {
244             *return_buf++ = (char)(out_buf[k] & 0x0ff);
245          }
246          j = 0;
247          bytes_decoded += bytes;
248       }
249    }
250    *return_buf = '\0';
251    return bytes_decoded;
252 }
253 
Base64Decode(buf)254 char *Base64Decode(buf)
255    char *buf;
256 {
257    int len=strlen(buf);
258    char *return_buf=(char*)malloc(len*sizeof(char));
259 
260    if (return_buf == NULL) {
261       FailAllocMessage();
262       return NULL;
263    }
264    (void)DoBase64Decode(buf, len, return_buf);
265 
266    return return_buf;
267 }
268 
269 static
BubbleAuthInfoToTop(pai)270 void BubbleAuthInfoToTop(pai)
271    struct AuthInfo *pai;
272 {
273    if (pai == topAuthInfo) return;
274    if (pai->next != NULL) {
275       pai->next->prev = pai->prev;
276    } else {
277       botAuthInfo = pai->prev;
278    }
279    pai->prev->next = pai->next;
280    pai->prev = NULL;
281    pai->next = topAuthInfo;
282    topAuthInfo = pai;
283 }
284 
FindAuthorization(pszHost,nPort,pszScheme,pszRealm)285 char *FindAuthorization(pszHost, nPort, pszScheme, pszRealm)
286    char *pszHost, *pszScheme, *pszRealm;
287    int nPort;
288 {
289    struct AuthInfo *pai;
290 
291    for (pai=topAuthInfo; pai != NULL; pai=pai->next) {
292       if (pai->port == nPort &&
293             pai->host != NULL && UtilStrICmp(pai->host, pszHost) == 0 &&
294             pai->scheme != NULL && UtilStrICmp(pai->scheme, pszScheme) == 0 &&
295             pai->realm != NULL && UtilStrICmp(pai->realm, pszRealm) == 0) {
296          BubbleAuthInfoToTop(pai);
297          return pai->authorization;
298       }
299    }
300    return NULL;
301 }
302 
CommitAuthorization()303 void CommitAuthorization()
304 {
305    struct AuthInfo *pai=(struct AuthInfo *)malloc(sizeof(struct AuthInfo));
306 
307    if (pai == NULL) {
308       FailAllocMessage();
309       return;
310    }
311    memset(pai, 0, sizeof(struct AuthInfo));
312    if (curAuthorization.host != NULL) {
313       pai->host = UtilStrDup(curAuthorization.host);
314    }
315    if (curAuthorization.scheme != NULL) {
316       pai->scheme = UtilStrDup(curAuthorization.scheme);
317    }
318    if (curAuthorization.realm != NULL) {
319       pai->realm = UtilStrDup(curAuthorization.realm);
320    }
321    if (curAuthorization.authorization != NULL) {
322       pai->authorization = UtilStrDup(curAuthorization.authorization);
323    }
324    pai->port = curAuthorization.port;
325    if (topAuthInfo != NULL) {
326       topAuthInfo->prev = pai;
327    } else {
328       botAuthInfo = pai;
329    }
330    pai->prev = NULL;
331    pai->next = topAuthInfo;
332    topAuthInfo = pai;
333 }
334 
ResetAuthorization()335 void ResetAuthorization()
336 {
337    if (curAuthorization.host != NULL) free(curAuthorization.host);
338    if (curAuthorization.scheme != NULL) free(curAuthorization.scheme);
339    if (curAuthorization.realm != NULL) free(curAuthorization.realm);
340    if (curAuthorization.authorization != NULL) {
341       free(curAuthorization.authorization);
342    }
343    memset(&curAuthorization, 0, sizeof(struct AuthInfo));
344 }
345 
SetAuthorization(pszHost,nPort,pszScheme,pszRealm,pszEncodedAuth)346 int SetAuthorization(pszHost, nPort, pszScheme, pszRealm, pszEncodedAuth)
347    char *pszHost, *pszScheme, *pszRealm, *pszEncodedAuth;
348    int nPort;
349 {
350    ResetAuthorization();
351    curAuthorization.host = UtilStrDup(pszHost);
352    curAuthorization.scheme = UtilStrDup(pszScheme);
353    curAuthorization.realm = UtilStrDup(pszRealm);
354    curAuthorization.authorization = UtilStrDup(pszEncodedAuth);
355    curAuthorization.port = nPort;
356    if (curAuthorization.host==NULL || curAuthorization.scheme==NULL ||
357          curAuthorization.realm==NULL || curAuthorization.authorization==NULL) {
358       ResetAuthorization();
359       return FALSE;
360    }
361    return TRUE;
362 }
363 
HttpClearReferer()364 void HttpClearReferer()
365 {
366    RefererInfo *pri=topReferer;
367 
368 #ifdef _TGIF_DBG /* debug, do not translate */
369    TgAssert(pri != NULL, "NULL topReferer in HttpClearReferer()", NULL);
370 #endif /* TGIF_DBG */
371    if (pri == NULL) return;
372    pri = pri->next;
373    UtilFree(topReferer->referer);
374    free(topReferer);
375    topReferer = pri;
376 }
377 
HttpSetReferer(buf)378 void HttpSetReferer(buf)
379    char *buf;
380 {
381    RefererInfo *pri=(RefererInfo*)malloc(sizeof(RefererInfo));
382 
383    if (pri == NULL) FailAllocMessage();
384    pri->next = topReferer;
385    pri->referer = UtilStrDup(buf);
386    if (pri->referer == NULL) FailAllocMessage();
387    topReferer = pri;
388 }
389 
HttpFakeReferer(buf)390 void HttpFakeReferer(buf)
391    char *buf;
392 {
393    UtilFree(gpszFakedReferer);
394    gpszFakedReferer = NULL;
395    if (buf != NULL && *buf != '\0') {
396       gpszFakedReferer = UtilStrDup(buf);
397       if (gpszFakedReferer == NULL) FailAllocMessage();
398    }
399 }
400 
401 static
CleanUpHttpReferer()402 void CleanUpHttpReferer()
403 {
404    while (topReferer != NULL) {
405       HttpClearReferer();
406    }
407 }
408 
409 static
CleanUpHttpHeaderInfo()410 void CleanUpHttpHeaderInfo()
411 {
412    struct TgifHttpLineInfo *pthli, *next_thli;
413 
414    if (tgifHttpHeaderInfo.version != NULL) free(tgifHttpHeaderInfo.version);
415    if (tgifHttpHeaderInfo.resp_status != NULL) {
416       free(tgifHttpHeaderInfo.resp_status);
417    }
418    if (tgifHttpHeaderInfo.last_modified != NULL) {
419       free(tgifHttpHeaderInfo.last_modified);
420    }
421    if (tgifHttpHeaderInfo.server != NULL) free(tgifHttpHeaderInfo.server);
422    if (tgifHttpHeaderInfo.connection != NULL) {
423       free(tgifHttpHeaderInfo.connection);
424    }
425    if (tgifHttpHeaderInfo.location != NULL) free(tgifHttpHeaderInfo.location);
426    if (tgifHttpHeaderInfo.www_authenticate != NULL) {
427       free(tgifHttpHeaderInfo.www_authenticate);
428    }
429    if (tgifHttpHeaderInfo.content_encoding != NULL) {
430       free(tgifHttpHeaderInfo.content_encoding);
431    }
432    if (tgifHttpHeaderInfo.content_type != NULL) {
433       free(tgifHttpHeaderInfo.content_type);
434    }
435    for (pthli=tgifHttpHeaderInfo.misc; pthli != NULL; pthli=next_thli) {
436       next_thli = pthli->next;
437       if (pthli->name != NULL) free(pthli->name);
438       if (pthli->value != NULL) free(pthli->value);
439       free(pthli);
440    }
441    memset(&tgifHttpHeaderInfo, 0, sizeof(struct TgifHttpHeaderInfo));
442 }
443 
CleanUpHttp()444 void CleanUpHttp()
445 {
446    ResetAuthorization();
447    CleanUpAuthInfo();
448    CleanUpHttpHeaderInfo();
449    CleanUpHttpReferer();
450 
451    UtilFree(gpszFakedReferer);
452    gpszFakedReferer = NULL;
453 }
454 
InitHttp()455 void InitHttp()
456 {
457    topAuthInfo = botAuthInfo = NULL;
458    memset(&curAuthorization, 0, sizeof(struct AuthInfo));
459    memset(&tgifHttpHeaderInfo, 0, sizeof(struct TgifHttpHeaderInfo));
460    topReferer = NULL;
461 }
462 
HttpHeaderGetVersion()463 char *HttpHeaderGetVersion() { return tgifHttpHeaderInfo.version; }
464 
HttpHeaderGetResponseCode()465 int HttpHeaderGetResponseCode() { return tgifHttpHeaderInfo.resp_code; }
466 
HttpHeaderGetResponseStatus()467 char *HttpHeaderGetResponseStatus() { return tgifHttpHeaderInfo.resp_status; }
468 
HttpHeaderGetLastModified()469 char *HttpHeaderGetLastModified() { return tgifHttpHeaderInfo.last_modified; }
470 
HttpHeaderGetServer()471 char *HttpHeaderGetServer() { return tgifHttpHeaderInfo.server; }
472 
HttpHeaderGetConnection()473 char *HttpHeaderGetConnection() { return tgifHttpHeaderInfo.connection; }
474 
HttpHeaderGetLocation()475 char *HttpHeaderGetLocation() { return tgifHttpHeaderInfo.location; }
476 
HttpHeaderGetWWWAuthentication()477 char *HttpHeaderGetWWWAuthentication()
478 {
479    return tgifHttpHeaderInfo.www_authenticate;
480 }
481 
HttpHeaderGetContentEncoding()482 char *HttpHeaderGetContentEncoding()
483 {
484    return tgifHttpHeaderInfo.content_encoding;
485 }
486 
HttpHeaderGetContentType()487 char *HttpHeaderGetContentType() { return tgifHttpHeaderInfo.content_type; }
488 
HttpHeaderGetContentLength()489 long HttpHeaderGetContentLength() { return tgifHttpHeaderInfo.content_length; }
490 
HttpHeaderGetOtherField(name)491 char *HttpHeaderGetOtherField(name)
492    char *name;
493 {
494    struct TgifHttpLineInfo *pthli;
495 
496    for (pthli=tgifHttpHeaderInfo.misc; pthli != NULL; pthli=pthli->next) {
497       if (pthli->name != NULL && UtilStrICmp(pthli->name, name) == 0) {
498          return pthli->value;
499       }
500    }
501    return NULL;
502 }
503 
504 static int gnUserAgentNameInitialized=FALSE;
505 
506 static
InitUserAgentName()507 void InitUserAgentName()
508 {
509    if (gnUserAgentNameInitialized) return;
510    gnUserAgentNameInitialized = TRUE;
511 
512    GetClientID(SZ_USER_AGENT, sizeof(SZ_USER_AGENT));
513    GetUserID(SZ_USER_NAME, sizeof(SZ_USER_NAME));
514 }
515 
HttpDoConnect(psz_host,us_port,pn_socket)516 int HttpDoConnect(psz_host, us_port, pn_socket)
517    char *psz_host;
518    int us_port, *pn_socket;
519 {
520    int rc, len=strlen(psz_host)+80;
521    char *msg=(char*)malloc((len+1)*sizeof(char));
522 
523    if (msg == NULL) {
524       FailAllocMessage();
525       return TG_REMOTE_STATUS_MEM;
526    }
527    sprintf(msg, TgLoadCachedString(CSTID_MAKING_CONN_TO_HOST_PORT),
528          "HTTP", psz_host, us_port);
529    ShowRemoteStatus(msg);
530 
531    rc = TcpDoConnect(psz_host, us_port, pn_socket);
532 
533    if (rc == TG_REMOTE_STATUS_OK) {
534       sprintf(msg, TgLoadCachedString(CSTID_CONN_TO_HOST_PORT_ESTB),
535             "HTTP", psz_host, us_port);
536    } else {
537       sprintf(msg, TgLoadString(STID_FAIL_TO_CONN_TO_HOST_PORT),
538             "HTTP", psz_host, us_port);
539    }
540    ShowRemoteStatus(msg);
541    free(msg);
542 
543    return rc;
544 }
545 
546 static
AppendSimpleString(buf,name,value)547 char *AppendSimpleString(buf, name, value)
548    char *buf, *name, *value;
549 {
550    int cur_len=strlen(buf);
551 
552    if (name == NULL && value == NULL) {
553       int new_len=cur_len+2;
554 
555       if ((buf=(char*)realloc(buf, new_len+1)) == NULL) {
556          return NULL;
557       }
558       sprintf(&buf[cur_len], "\r\n");
559    } else {
560       int new_len=cur_len+strlen(name)+2+strlen(value)+2;
561 
562       if ((buf=(char*)realloc(buf, new_len+1)) == NULL) {
563          return NULL;
564       }
565       sprintf(&buf[cur_len], "%s: %s\r\n", name, value);
566    }
567    return buf;
568 }
569 
570 /* do not translate -- program constants */
571 static char SZ_CONTENT_TYPE[]="Content-type:";
572 static char SZ_CONTENT_LENGTH[]="Content-length:";
573 static char SZ_POST_CONTENT_TYPE[]="application/x-www-form-urlencoded";
574 
575 static char *pszAccept[] = {
576 /* "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png", */
577    "text/plain",
578    "text/html",
579    "application/x-tgif",
580    "*/*",
581    NULL
582 };
583 
584 static
AppendAcceptStrings(buf)585 char *AppendAcceptStrings(buf)
586    char *buf;
587 {
588    char **s_ptr;
589    int cur_len=strlen(buf);
590 
591    for (s_ptr=pszAccept; *s_ptr != NULL; s_ptr++) {
592       int len=strlen(*s_ptr);
593       int new_len=cur_len+len+2+8;
594 
595       if ((buf=(char*)realloc(buf, new_len+1)) == NULL) {
596          return NULL;
597       }
598       /* do not translate -- program constants */
599       sprintf(&buf[cur_len], "Accept: %s\r\n", *s_ptr);
600       cur_len = new_len;
601    }
602    return buf;
603 }
604 
605 static
AppendKeepAliveStrings(buf)606 char *AppendKeepAliveStrings(buf)
607    char *buf;
608 {
609    if (gnHttpKeepAlive == FALSE) return buf;
610 
611    /* do not translate -- program constants */
612    return AppendSimpleString(buf, "Connection", "Keep-Alive");
613 }
614 
615 static
AppendRefererStrings(buf)616 char *AppendRefererStrings(buf)
617    char *buf;
618 {
619    if (topReferer == NULL) {
620       if (gpszFakedReferer == NULL) {
621          return buf;
622       }
623       /* do not translate -- program constants */
624       return AppendSimpleString(buf, "Referer", gpszFakedReferer);
625    }
626    /* do not translate -- program constants */
627    return AppendSimpleString(buf, "Referer", topReferer->referer);
628 }
629 
630 static
AppendUserAgentString(buf)631 char *AppendUserAgentString(buf)
632    char *buf;
633 {
634    InitUserAgentName();
635    /* do not translate -- program constants */
636    return AppendSimpleString(buf, "User-Agent", SZ_USER_AGENT);
637 }
638 
639 static
AppendFromString(buf)640 char *AppendFromString(buf)
641    char *buf;
642 {
643    InitUserAgentName();
644    /* do not translate -- program constants */
645    return AppendSimpleString(buf, "From", SZ_USER_NAME);
646 }
647 
648 static
AppendHostString(buf,psz_host,us_port)649 char *AppendHostString(buf, psz_host, us_port)
650    char *buf, *psz_host;
651    int us_port;
652 {
653    char tmp_buf[MAXSTRING];
654 
655    sprintf(tmp_buf, "%s:%1d", psz_host, us_port);
656    /* do not translate -- program constants */
657    return AppendSimpleString(buf, "Host", tmp_buf);
658 }
659 
660 static
AppendAuthorizationString(buf)661 char *AppendAuthorizationString(buf)
662    char *buf;
663 {
664    char *pszReturn;
665    char *pszAuth=(char*)malloc(
666          (strlen(curAuthorization.scheme)+
667          strlen(curAuthorization.authorization)+2)*sizeof(char));
668 
669    if (pszAuth == NULL) return NULL;
670    sprintf(pszAuth, "%s %s", curAuthorization.scheme,
671          curAuthorization.authorization);
672    /* do not translate -- program constants */
673    pszReturn = AppendSimpleString(buf, "Authorization", pszAuth);
674    free(pszAuth);
675    return pszReturn;
676 }
677 
678 static
AppendPostContentTypeString(buf)679 char *AppendPostContentTypeString(buf)
680    char *buf;
681 {
682    /* do not translate -- program constants */
683    return AppendSimpleString(buf, "Content-type", SZ_POST_CONTENT_TYPE);
684 }
685 
686 static
AppendPostContentLengthString(buf,content_length)687 char *AppendPostContentLengthString(buf, content_length)
688    char *buf;
689    int content_length;
690 {
691    char len_str[20];
692 
693    sprintf(len_str, "%1d", content_length);
694    /* do not translate -- program constants */
695    return AppendSimpleString(buf, "Content-length", len_str);
696 }
697 
698 static
AppendPostContentString(buf,fp,content_length)699 char *AppendPostContentString(buf, fp, content_length)
700    char *buf;
701    FILE *fp;
702    int content_length;
703 {
704    int cur_len=strlen(buf), bytes_read, total_read=0;
705    int new_len=cur_len+content_length;
706    char tmp_buf[512];
707 
708    if ((buf=(char*)realloc(buf, new_len+1)) == NULL) {
709       return NULL;
710    }
711    while ((bytes_read=fread(tmp_buf, sizeof(char), sizeof(tmp_buf),
712          fp)) > 0) {
713       if (bytes_read+total_read > content_length) {
714          bytes_read = content_length-total_read;
715          fprintf(stderr, TgLoadString(STID_LINES_TOO_LONG_CONTENT_LENGTH),
716                "HTTP");
717          fprintf(stderr, "\n");
718       }
719       strncpy(&buf[cur_len+total_read], tmp_buf, bytes_read);
720       total_read += bytes_read;
721    }
722    buf[cur_len+content_length] = '\0';
723    return buf;
724 }
725 
726 static
AppendCRLFString(buf)727 char *AppendCRLFString(buf)
728    char *buf;
729 {
730    return AppendSimpleString(buf, NULL, NULL);
731 }
732 
HttpDoWrite(n_socket,psz_path,psz_host,us_port)733 int HttpDoWrite(n_socket, psz_path, psz_host, us_port)
734    int n_socket, us_port;
735    char *psz_path, *psz_host;
736 {
737    int status=0, total_sz=0;
738    FILE *fp=NULL;
739    char *buf=(char*)malloc((strlen(psz_path)+5+2+31)*sizeof(char)), msg[40];
740 
741    if (buf == NULL) {
742       FailAllocMessage();
743       return TG_REMOTE_STATUS_MEM;
744    }
745    if (postingCGIQuery) {
746       /* do not translate -- program constants */
747       sprintf(buf, "POST %s %s\r\n", psz_path, SZ_HTTP_VERSION);
748    } else if (gettingHttpHeaderOnly) {
749       /* do not translate -- program constants */
750       sprintf(buf, "HEAD %s %s\r\n", psz_path, SZ_HTTP_VERSION);
751    } else {
752       /* do not translate -- program constants */
753       sprintf(buf, "GET %s %s\r\n", psz_path, SZ_HTTP_VERSION);
754    }
755    if ((buf=AppendKeepAliveStrings(buf)) == NULL) {
756       FailAllocMessage();
757       return TG_REMOTE_STATUS_MEM;
758    }
759    if ((buf=AppendRefererStrings(buf)) == NULL) {
760       FailAllocMessage();
761       return TG_REMOTE_STATUS_MEM;
762    }
763    if ((buf=AppendAcceptStrings(buf)) == NULL) {
764       FailAllocMessage();
765       return TG_REMOTE_STATUS_MEM;
766    }
767    if ((buf=AppendUserAgentString(buf)) == NULL) {
768       FailAllocMessage();
769       return TG_REMOTE_STATUS_MEM;
770    }
771    if ((buf=AppendFromString(buf)) == NULL) {
772       FailAllocMessage();
773       return TG_REMOTE_STATUS_MEM;
774    }
775    if ((buf=AppendHostString(buf, psz_host, us_port)) == NULL) {
776       FailAllocMessage();
777       return TG_REMOTE_STATUS_MEM;
778    }
779    if (curAuthorization.scheme != NULL &&
780          curAuthorization.authorization != NULL) {
781       if ((buf=AppendAuthorizationString(buf)) == NULL) {
782          FailAllocMessage();
783          return TG_REMOTE_STATUS_MEM;
784       }
785    }
786    if (postingCGIQuery && fnameForPostingCGIQuery != NULL) {
787       int bytes_read;
788       char tmp_buf[512];
789 
790       if ((fp=fopen(fnameForPostingCGIQuery, "r")) == NULL) {
791          fprintf(stderr, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_READING),
792                fnameForPostingCGIQuery);
793          fprintf(stderr, "\n");
794          return TG_REMOTE_STATUS_READ;
795       }
796       while ((bytes_read=fread(tmp_buf, sizeof(char), sizeof(tmp_buf),
797             fp)) > 0) {
798          total_sz += bytes_read;
799       }
800       rewind(fp);
801       if ((buf=AppendPostContentTypeString(buf)) == NULL) {
802          fclose(fp);
803          FailAllocMessage();
804          return TG_REMOTE_STATUS_MEM;
805       }
806       if ((buf=AppendPostContentLengthString(buf, total_sz)) == NULL) {
807          fclose(fp);
808          FailAllocMessage();
809          return TG_REMOTE_STATUS_MEM;
810       }
811    }
812    if ((buf=AppendCRLFString(buf)) == NULL) {
813       FailAllocMessage();
814       return TG_REMOTE_STATUS_MEM;
815    }
816    if (fp != NULL) {
817       buf = AppendPostContentString(buf, fp, total_sz);
818       fclose(fp);
819       if (buf == NULL) {
820          FailAllocMessage();
821          return TG_REMOTE_STATUS_MEM;
822       }
823    }
824    sprintf(msg, TgLoadCachedString(CSTID_SENDING_REQUESTS_DOTS), "HTTP");
825    ShowRemoteStatus(msg);
826 
827    if (debugHttp == 999 || ((debugHttp % 100) == 99 && cmdLineDumpURL &&
828          cmdLineDumpURLWithHeader)) {
829       /* debug, do not translate */
830       fprintf(stderr, "************************\n");
831       fprintf(stderr, "* Begin Request Header *\n");
832       fprintf(stderr, "************************\n");
833       (void)fwrite(buf, sizeof(char), strlen(buf), stderr);
834       fprintf(stderr, "************************\n");
835       fprintf(stderr, "*  End Request Header  *\n");
836       fprintf(stderr, "************************\n");
837    }
838    status = TcpDoWrite(n_socket, buf, (int)strlen(buf));
839    free(buf);
840 
841    if (status != TG_REMOTE_STATUS_OK) {
842       sprintf(msg, TgLoadString(STID_FAIL_TO_SEND_REQ), "HTTP");
843       ShowRemoteStatus(msg);
844    }
845    return status;
846 }
847 
848 #ifdef NOT_DEFINED
849 #ifdef _TGIF_DBG /* debug, do not translate */
850 static char SZ_DEF_GIF_NAME[]="/tmp/htclient.gif";
851 
852 static
DebugHttpDumpResponse(buf)853 void DebugHttpDumpResponse(buf)
854    char *buf;
855 {
856    char *c_ptr=strchr(buf, '\n'), *line_ptr=buf, *content_type=NULL;
857    int content_length=(-1), gif87a=FALSE;
858    int len1=strlen(SZ_CONTENT_TYPE), len2=strlen(SZ_CONTENT_LENGTH);
859    FILE *fp=stderr;
860 
861    while (c_ptr != NULL) {
862       char *prev_ptr=c_ptr;
863 
864       if (prev_ptr != line_ptr && *(--prev_ptr) == '\r') {
865          *prev_ptr = '\0';
866       } else {
867          prev_ptr = NULL;
868          *c_ptr = '\0';
869       }
870       fprintf(fp, "%s\n", line_ptr);
871       if (content_type == NULL &&
872             UtilStrNCaseCmp(line_ptr, SZ_CONTENT_TYPE, len1) == 0) {
873          content_type = UtilStrDup(&line_ptr[len1]);
874          if (content_type != NULL) {
875             UtilTrimBlanks(content_type);
876          }
877       } else if (content_length == (-1) &&
878             UtilStrNCaseCmp(line_ptr, SZ_CONTENT_LENGTH, len2) == 0) {
879          char *tmp_ptr=UtilStrDup(&line_ptr[len2]);
880 
881          if (tmp_ptr != NULL) {
882             UtilTrimBlanks(tmp_ptr);
883             content_length = atoi(tmp_ptr);
884             free(tmp_ptr);
885          }
886       }
887       if (prev_ptr == NULL) {
888          *c_ptr = '\n';
889       } else {
890          *prev_ptr = '\r';
891       }
892       line_ptr = &c_ptr[1];
893       if (content_type != NULL && content_length != (-1)) {
894          /* do not translate -- program constants */
895          if (UtilStrICmp(content_type, "image/gif") == 0 &&
896                UtilStrNCaseCmp(line_ptr, "GIF87a", 6) == 0) {
897             gif87a = TRUE;
898             break;
899          }
900       }
901       c_ptr = strchr(line_ptr, '\n');
902    }
903    if (gif87a) {
904       FILE *gif_fp;
905 
906       if ((gif_fp=fopen(SZ_DEF_GIF_NAME, "w")) == NULL) {
907          fprintf(stderr, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
908                SZ_DEF_GIF_NAME);
909          fprintf(stderr, "\n");
910       } else {
911          if (fwrite(line_ptr, sizeof(char), content_length, gif_fp) !=
912                content_length) {
913             FailToWriteFileMessage(SZ_DEF_GIF_NAME);
914          } else {
915             /* debug, do not translate */
916             fprintf(stderr, "GIF87a image written to '%s'.\n", SZ_DEF_GIF_NAME);
917          }
918          fclose(gif_fp);
919       }
920    } else if (line_ptr != NULL) {
921       int len=strlen(line_ptr);
922 
923       if (len > 0 && line_ptr[len-1] == '\r') {
924          line_ptr[len-1] = '\0';
925          fprintf(fp, "%s\n", line_ptr);
926          line_ptr[len-1] = '\r';
927       } else {
928          fprintf(fp, "%s\n", line_ptr);
929       }
930    }
931 }
932 #endif /* _TGIF_DBG */
933 #endif /* NOT_DEFINED */
934 
935 static
ParseBadFormat(buf)936 int ParseBadFormat(buf)
937    char *buf;
938 {
939    fprintf(stderr, TgLoadString(STID_INVALID_FORMAT_IN_HEADER), "HTTP");
940    fprintf(stderr, "\n");
941    if (buf != NULL) free(buf);
942    return TG_REMOTE_STATUS_FORMAT;
943 }
944 
945 static
ParseNoMem(buf)946 int ParseNoMem(buf)
947    char *buf;
948 {
949    FailAllocMessage();
950    if (buf != NULL) free(buf);
951    return TG_REMOTE_STATUS_MEM;
952 }
953 
954 static
HttpParseHeaderLine(buf,first_line)955 int HttpParseHeaderLine(buf, first_line)
956    char *buf;
957    int first_line;
958 {
959    char *dup_buf, *colon_ptr;
960 
961    if (*buf == '\0') return TG_REMOTE_STATUS_OK;
962 
963    if (first_line) {
964       char *version_ptr, *code_ptr, *status_ptr;
965 
966       dup_buf = UtilStrDup(buf);
967       if (dup_buf == NULL) return ParseNoMem(NULL);;
968       version_ptr = strtok(dup_buf, " \t\n\r");
969       code_ptr = (version_ptr == NULL ? NULL : strtok(NULL, " \t\n\r"));
970       status_ptr = (code_ptr == NULL ? NULL : strtok(NULL, " \t\n\r"));
971       if (version_ptr == NULL) return ParseBadFormat(dup_buf);
972       tgifHttpHeaderInfo.version = UtilStrDup(version_ptr);
973       if (code_ptr == NULL) return ParseBadFormat(dup_buf);
974       tgifHttpHeaderInfo.resp_code = atoi(code_ptr);
975       if (status_ptr != NULL) {
976          tgifHttpHeaderInfo.resp_status = UtilStrDup(status_ptr);
977          if (tgifHttpHeaderInfo.resp_status == NULL) {
978             return ParseBadFormat(dup_buf);
979          }
980       }
981       free(dup_buf);
982       return TG_REMOTE_STATUS_OK;
983    }
984    dup_buf = UtilStrDup(buf);
985    if (dup_buf == NULL) return ParseNoMem(NULL);
986 
987    colon_ptr = strchr(dup_buf, ':');
988    if (colon_ptr == NULL) return ParseBadFormat(dup_buf);
989    *colon_ptr = '\0';
990    UtilTrimBlanks(dup_buf);
991    /* do not translate -- program constants */
992    if (UtilStrICmp(dup_buf, "Last-Modified") == 0) {
993       tgifHttpHeaderInfo.last_modified = UtilStrDup(&colon_ptr[1]);
994       if (tgifHttpHeaderInfo.last_modified == NULL) return ParseNoMem(dup_buf);;
995       UtilTrimBlanks(tgifHttpHeaderInfo.last_modified);
996    } else if (UtilStrICmp(dup_buf, "Server") == 0) {
997       tgifHttpHeaderInfo.server = UtilStrDup(&colon_ptr[1]);
998       if (tgifHttpHeaderInfo.server == NULL) return ParseNoMem(dup_buf);;
999       UtilTrimBlanks(tgifHttpHeaderInfo.server);
1000    } else if (UtilStrICmp(dup_buf, "Connection") == 0) {
1001       tgifHttpHeaderInfo.connection = UtilStrDup(&colon_ptr[1]);
1002       if (tgifHttpHeaderInfo.connection == NULL) return ParseNoMem(dup_buf);;
1003       UtilTrimBlanks(tgifHttpHeaderInfo.connection);
1004    } else if (UtilStrICmp(dup_buf, "Location") == 0) {
1005       tgifHttpHeaderInfo.location = UtilStrDup(&colon_ptr[1]);
1006       if (tgifHttpHeaderInfo.location == NULL) return ParseNoMem(dup_buf);;
1007       UtilTrimBlanks(tgifHttpHeaderInfo.location);
1008    } else if (UtilStrICmp(dup_buf, "WWW-Authenticate") == 0) {
1009       tgifHttpHeaderInfo.www_authenticate = UtilStrDup(&colon_ptr[1]);
1010       if (tgifHttpHeaderInfo.www_authenticate == NULL) {
1011          return ParseNoMem(dup_buf);;
1012       }
1013       UtilTrimBlanks(tgifHttpHeaderInfo.www_authenticate);
1014    } else if (UtilStrICmp(dup_buf, "Content-Encoding") == 0) {
1015       tgifHttpHeaderInfo.content_encoding = UtilStrDup(&colon_ptr[1]);
1016       if (tgifHttpHeaderInfo.content_encoding == NULL) {
1017          return ParseNoMem(dup_buf);;
1018       }
1019       UtilTrimBlanks(tgifHttpHeaderInfo.content_encoding);
1020    } else if (UtilStrICmp(dup_buf, "Content-Type") == 0) {
1021       tgifHttpHeaderInfo.content_type = UtilStrDup(&colon_ptr[1]);
1022       if (tgifHttpHeaderInfo.content_type == NULL) return ParseNoMem(dup_buf);;
1023       UtilTrimBlanks(tgifHttpHeaderInfo.content_type);
1024    } else if (UtilStrICmp(dup_buf, "Content-Length") == 0) {
1025       char *length_ptr=(&colon_ptr[1]);
1026 
1027       UtilTrimBlanks(length_ptr);
1028       if (sscanf(length_ptr, "%ld", &tgifHttpHeaderInfo.content_length) != 1) {
1029          tgifHttpHeaderInfo.content_length = 0L;
1030       }
1031    } else {
1032       struct TgifHttpLineInfo *pthli;
1033 
1034       pthli = (struct TgifHttpLineInfo*)malloc(sizeof(struct TgifHttpLineInfo));
1035       if (pthli == NULL) return ParseNoMem(dup_buf);;
1036       memset(pthli, 0, sizeof(struct TgifHttpLineInfo));
1037       pthli->name = UtilStrDup(dup_buf);
1038       if (pthli->name == NULL) return ParseNoMem(dup_buf);;
1039       pthli->value = UtilStrDup(&colon_ptr[1]);
1040       if (pthli->value == NULL) return ParseNoMem(dup_buf);;
1041       pthli->next = tgifHttpHeaderInfo.misc;
1042       tgifHttpHeaderInfo.misc = pthli;
1043    }
1044    *colon_ptr = ':';
1045    free(dup_buf);
1046    return TG_REMOTE_STATUS_OK;
1047 }
1048 
HttpDumpHeader()1049 void HttpDumpHeader()
1050 {
1051    struct TgifHttpLineInfo *pthli;
1052 
1053    if (tgifHttpHeaderInfo.version != NULL) {
1054       fprintf(stderr, "%s %1d", tgifHttpHeaderInfo.version,
1055             tgifHttpHeaderInfo.resp_code);
1056       if (tgifHttpHeaderInfo.resp_status != NULL) {
1057          fprintf(stderr, " %s", tgifHttpHeaderInfo.resp_status);
1058       }
1059       fprintf(stderr, "\n");
1060    }
1061    /* do not translate -- program constants */
1062    if (tgifHttpHeaderInfo.last_modified != NULL) {
1063       fprintf(stderr, "Last-Modified: %s\n", tgifHttpHeaderInfo.last_modified);
1064    }
1065    if (tgifHttpHeaderInfo.server != NULL) {
1066       fprintf(stderr, "Server: %s\n", tgifHttpHeaderInfo.server);
1067    }
1068    if (tgifHttpHeaderInfo.connection != NULL) {
1069       fprintf(stderr, "Connection: %s\n", tgifHttpHeaderInfo.connection);
1070    }
1071    if (tgifHttpHeaderInfo.location != NULL) {
1072       fprintf(stderr, "Location: %s\n", tgifHttpHeaderInfo.location);
1073    }
1074    if (tgifHttpHeaderInfo.www_authenticate != NULL) {
1075       fprintf(stderr, "WWW-Authentication: %s\n",
1076             tgifHttpHeaderInfo.www_authenticate);
1077    }
1078    if (tgifHttpHeaderInfo.content_encoding != NULL) {
1079       fprintf(stderr, "Content-Encoding: %s\n",
1080             tgifHttpHeaderInfo.content_encoding);
1081    }
1082    if (tgifHttpHeaderInfo.content_type != NULL) {
1083       fprintf(stderr, "Content-Type: %s\n", tgifHttpHeaderInfo.content_type);
1084    }
1085    if (tgifHttpHeaderInfo.content_length != 0) {
1086       fprintf(stderr, "Content-Length: %ld\n",
1087             tgifHttpHeaderInfo.content_length);
1088    }
1089    for (pthli=tgifHttpHeaderInfo.misc; pthli != NULL; pthli=pthli->next) {
1090       fprintf(stderr, "%s: %s\n",
1091             (pthli->name == NULL ? TgLoadCachedString(CSTID_PARANED_UNKNOWN) :
1092             pthli->name), (pthli->value == NULL ?
1093             TgLoadCachedString(CSTID_PARANED_NONE) : pthli->value));
1094    }
1095 }
1096 
HttpExtractText(buf,pn_buf_sz,pn_html,ppsz_content_type)1097 char *HttpExtractText(buf, pn_buf_sz, pn_html, ppsz_content_type)
1098    char *buf, **ppsz_content_type;
1099    int *pn_buf_sz, *pn_html;
1100 {
1101    char *c_ptr=strchr(buf, '\n'), *line_ptr=buf, *content_type=NULL;
1102    int content_length=(-1), text_type=FALSE, first_line=TRUE;
1103    int len1=strlen(SZ_CONTENT_TYPE), len2=strlen(SZ_CONTENT_LENGTH);
1104    FILE *fp=stderr;
1105 
1106    CleanUpHttpHeaderInfo();
1107 
1108    if (pn_buf_sz != NULL) *pn_buf_sz = 0;
1109    if (pn_html != NULL) *pn_html = FALSE;
1110    if (ppsz_content_type != NULL) *ppsz_content_type = NULL;
1111    while (c_ptr != NULL) {
1112       char *prev_ptr=c_ptr;
1113       int rc;
1114 
1115       if (prev_ptr != line_ptr && *(--prev_ptr) == '\r') {
1116          *prev_ptr = '\0';
1117       } else {
1118          prev_ptr = NULL;
1119          *c_ptr = '\0';
1120       }
1121       if (debugHttp > 0) {
1122          if ((debugHttp % 100) == 99 && cmdLineDumpURL &&
1123                !cmdLineDumpURLWithHeader) {
1124          } else if (!deserializingFile) {
1125             fprintf(fp, "%s\n", line_ptr);
1126          }
1127       }
1128       rc = HttpParseHeaderLine(line_ptr, first_line);
1129       if (rc != TG_REMOTE_STATUS_OK) {
1130          /* well, should break... */
1131       }
1132       first_line = FALSE;
1133       if (*line_ptr == '\0') {
1134          /* empty line, end of header */
1135          if (prev_ptr == NULL) {
1136             *c_ptr = '\n';
1137          } else {
1138             *prev_ptr = '\r';
1139          }
1140          line_ptr = &c_ptr[1];
1141          break;
1142       }
1143       if (content_type == NULL &&
1144             UtilStrNCaseCmp(line_ptr, SZ_CONTENT_TYPE, len1) == 0) {
1145          content_type = UtilStrDup(&line_ptr[len1]);
1146          if (content_type != NULL) {
1147             char *psz;
1148 
1149             UtilTrimBlanks(content_type);
1150             if ((psz=strchr(content_type, ';')) != NULL) *psz = '\0';
1151             if (ppsz_content_type != NULL) {
1152                *ppsz_content_type = UtilStrDup(content_type);
1153             }
1154             /* do not translate -- program constants */
1155             if (UtilStrNCaseCmp(content_type, "text/", 5) == 0) {
1156                text_type = TRUE;
1157                if (strcmp(&content_type[5], "html") == 0) {
1158                   if (pn_html != NULL) *pn_html = TRUE;
1159                }
1160             }
1161          }
1162       } else if (content_length == (-1) &&
1163             UtilStrNCaseCmp(line_ptr, SZ_CONTENT_LENGTH, len2) == 0) {
1164          char *tmp_ptr=UtilStrDup(&line_ptr[len2]);
1165 
1166          if (tmp_ptr != NULL) {
1167             UtilTrimBlanks(tmp_ptr);
1168             content_length = atoi(tmp_ptr);
1169             free(tmp_ptr);
1170          }
1171       }
1172       if (prev_ptr == NULL) {
1173          *c_ptr = '\n';
1174       } else {
1175          *prev_ptr = '\r';
1176       }
1177       line_ptr = &c_ptr[1];
1178       c_ptr = strchr(line_ptr, '\n');
1179    }
1180    if (content_type != NULL) free(content_type);
1181    if (cmdLineDumpURL && cmdLineDumpURLWithHeader && cmdLineDumpURLHeaderOnly) {
1182       /* only want the header */
1183    } else if (text_type || content_length == (-1)) {
1184       int buf_len=strlen(line_ptr);
1185       char *return_buf;
1186 
1187       if (content_length == (-1)) {
1188          content_length = buf_len;
1189          return_buf = (char*)malloc((buf_len+1)*sizeof(char));
1190       } else {
1191          return_buf = (char*)malloc((content_length+1)*sizeof(char));
1192       }
1193       if (return_buf == NULL) {
1194          FailAllocMessage();
1195          return NULL;
1196       }
1197       if (buf_len <= content_length) {
1198          memcpy(return_buf, line_ptr, content_length);
1199       } else {
1200          while (buf_len > content_length) {
1201             if (*line_ptr == '\r' || *line_ptr == '\n') {
1202                line_ptr++;
1203                buf_len--;
1204             } else {
1205                break;
1206             }
1207          }
1208          memcpy(return_buf, line_ptr, content_length);
1209       }
1210       return_buf[content_length] = '\0';
1211       if (pn_buf_sz != NULL) *pn_buf_sz = content_length;
1212       return return_buf;
1213    } else if (content_length != (-1)) {
1214       char *return_buf=(char*)malloc((content_length+1)*sizeof(char));
1215 
1216       if (return_buf == NULL) {
1217          FailAllocMessage();
1218          return NULL;
1219       }
1220       memcpy(return_buf, line_ptr, content_length);
1221       return_buf[content_length] = '\0';
1222       if (pn_buf_sz != NULL) *pn_buf_sz = content_length;
1223       return return_buf;
1224    }
1225    return NULL;
1226 }
1227 
1228 static
GetContentLength(buf,pn_header_len)1229 int GetContentLength(buf, pn_header_len)
1230    char *buf;
1231    int *pn_header_len;
1232 {
1233    char *c_ptr, *line_ptr=buf;
1234    int content_len=(-1), just_lf=IsJustLF(buf);
1235    int inc=(just_lf?1:2);
1236 
1237    for (c_ptr=GetHeaderLine(line_ptr, just_lf); c_ptr != NULL;
1238          c_ptr=GetHeaderLine(line_ptr, just_lf)) {
1239       char *colon_ptr=NULL;
1240 
1241       if (c_ptr == line_ptr) {
1242          /* reach the end of header, now decide if the header is good */
1243          *pn_header_len = ((&c_ptr[inc]) - buf);
1244          return (content_len==(-1) ? 0 : content_len);
1245       }
1246       *c_ptr = '\0';
1247       colon_ptr = strchr(line_ptr, ':');
1248       if (colon_ptr != NULL) {
1249          *colon_ptr = '\0';
1250          /* do not translate -- program constants */
1251          if (UtilStrICmp(line_ptr, "Content-Length") == 0) {
1252             char length_str[MAXSTRING];
1253             int len=0;
1254 
1255             UtilStrCpyN(length_str, MAXSTRING-1, &colon_ptr[1]);
1256             UtilTrimBlanks(length_str);
1257             if (sscanf(length_str, "%d", &len) == 1) {
1258                content_len = len;
1259             }
1260          }
1261          *colon_ptr = ':';
1262       }
1263       *c_ptr = (just_lf ? '\n' : '\r');
1264       line_ptr = (&c_ptr[inc]);
1265    }
1266    return (-1);
1267 }
1268 
1269 static
ReadFromSocket(n_socket)1270 int ReadFromSocket(n_socket)
1271    int n_socket;
1272    /* return TRUE means there's data at n_socket */
1273    /* return FALSE means abort */
1274 {
1275    for (;;) {
1276       struct timeval timeout;
1277       fd_set fdset;
1278       int select_width=XConnectionNumber(mainDisplay)+1, status=0, nfds=0;
1279 
1280       nfds = max(select_width, n_socket+1);
1281 
1282       timeout.tv_sec = 0;
1283       timeout.tv_usec = 100000;
1284 
1285       FD_ZERO(&fdset);
1286       FD_SET(select_width-1, &fdset);
1287       FD_SET(n_socket, &fdset);
1288 #ifdef __hpux
1289       status = select(nfds, (int*)&fdset, NULL, NULL, &timeout);
1290 #else /* !__hpux */
1291       status = select(nfds, &fdset, NULL, NULL, &timeout);
1292 #endif /* __hpux */
1293       if (status < 0) {
1294          if (errno == EINTR) {
1295             /* interrupted by a system call, not a problem */
1296             CheckInterrupt(TRUE);
1297          } else {
1298             sprintf(gszMsgBox, TgLoadString(STID_FUNC_SELECT_SYS_CALL_FAILED),
1299                   "ReadFromSocket()"),
1300             MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1301             break;
1302          }
1303       } else if (status == 0) {
1304          /* spin the interrupt thing */
1305          CheckInterrupt(TRUE);
1306       } else if (status == 1) {
1307          if (FD_ISSET(n_socket, &fdset)) {
1308             /* character waiting to be processed at n_socket */
1309             return TRUE;
1310          } else if (FD_ISSET(select_width-1, &fdset)) {
1311             while (XPending(mainDisplay) > 0) {
1312                if (TryProcessAnAbortXEvent(TRUE, NULL, NULL) != 0) {
1313                   return FALSE;
1314                }
1315             }
1316          }
1317       } else if (status == 2) {
1318          return TRUE;
1319       } else {
1320          sprintf(gszMsgBox, TgLoadString(STID_FUNC_INVALID_RC_FOR_SELECT),
1321                "ReadFromSocket()", status);
1322          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1323          break;
1324       }
1325    }
1326    return FALSE;
1327 }
1328 
1329 #define MIN_READ_SIZE 0x100
1330 
HttpDoRead(n_socket,ppsz_buf,pn_buf_sz)1331 int HttpDoRead(n_socket, ppsz_buf, pn_buf_sz)
1332    int n_socket, *pn_buf_sz;
1333    char **ppsz_buf;
1334 {
1335    int buf_sz=0x400, len=0, end_of_file=FALSE;
1336    int status=TG_REMOTE_STATUS_OK, content_len=(-1), header_len=0;
1337    char *buf=(char*)malloc(buf_sz*sizeof(char)), msg[MAXSTRING];
1338 
1339    if (pn_buf_sz != NULL) *pn_buf_sz = 0;
1340    *ppsz_buf = NULL;
1341    if (buf == NULL) {
1342       FailAllocMessage();
1343       return TG_REMOTE_STATUS_MEM;
1344    }
1345    sprintf(msg, TgLoadCachedString(CSTID_READING_RESPONSE_DOTS), "HTTP");
1346    ShowRemoteStatus(msg);
1347    CleanUpDownloadStats();
1348    ResetMultipartReplace(FALSE);
1349 
1350    do {
1351       int bytes_read=0;
1352       char progress_buf[MAXSTRING];
1353 
1354       *progress_buf = '\0';
1355       if (buf_sz - len < MIN_READ_SIZE) {
1356          buf_sz += 0x400;
1357          if ((buf=(char*)realloc(buf, buf_sz)) == NULL) {
1358             FailAllocMessage();
1359             status = TG_REMOTE_STATUS_MEM;
1360             break;
1361          }
1362       }
1363       if (PRTGIF || ReadFromSocket(n_socket)) {
1364          bytes_read = read(n_socket, &buf[len], buf_sz-len-1);
1365       } else {
1366          /* abort */
1367          status = TG_REMOTE_STATUS_INTR;
1368          break;
1369       }
1370       if (bytes_read <= 0) {
1371          if (bytes_read < 0 && (errno == ENOTCONN || errno == ECONNRESET ||
1372                errno == EPIPE)) {
1373             fprintf(stderr, TgLoadString(STID_NETWORK_READ_ERROR), "HTTP");
1374             fprintf(stderr, "\n");
1375             status = TG_REMOTE_STATUS_READ;
1376          } else if (bytes_read < 0) {
1377             fprintf(stderr, TgLoadString(STID_NETWORK_ERROR), "HTTP");
1378             fprintf(stderr, "\n");
1379             status = TG_REMOTE_STATUS_NET;
1380          }
1381          if (!UpdateDownloadStats(0, progress_buf)) {
1382             *progress_buf = '\0';
1383          }
1384          end_of_file = TRUE;
1385       } else {
1386          if (!UpdateDownloadStats(bytes_read, progress_buf)) {
1387             *progress_buf = '\0';
1388          }
1389          len += bytes_read;
1390       }
1391       if (status == TG_REMOTE_STATUS_OK && !end_of_file &&
1392             (UserAbortComm() || OtherAbortComm())) {
1393          /* abort */
1394          status = TG_REMOTE_STATUS_INTR;
1395          break;
1396       } else {
1397          int chopped_len=(-1);
1398 
1399          if (status == TG_REMOTE_STATUS_OK && content_len == (-1)) {
1400             buf[len] = '\0';
1401             content_len = GetContentLength(buf, &header_len);
1402          }
1403          if (content_len == (-1) || content_len == 0) {
1404             /* do not translate -- program constants */
1405             sprintf(msg, "HTTP: %1d bytes %s...", len,
1406                   (*progress_buf=='\0' ? "" : progress_buf));
1407             if (len >= 200) {
1408                chopped_len = len;
1409                HandleMultipartReplace(buf, &chopped_len);
1410             }
1411          } else {
1412             /* do not translate -- program constants */
1413             sprintf(msg, "HTTP: %1d of %1d bytes %s...", len-header_len,
1414                   content_len, (*progress_buf=='\0' ? "" : progress_buf));
1415             if (status == TG_REMOTE_STATUS_OK &&
1416                   len == header_len+content_len) {
1417                end_of_file = TRUE;
1418             }
1419          }
1420          ShowRemoteStatus(msg);
1421          if (PRTGIF && cmdLineDumpURL && cmdLineDumpURLShowStatus) {
1422             if (content_len == (-1) || content_len == 0) {
1423                /* do not translate -- program constants */
1424                fprintf(stderr, "HTTP: %1d bytes %s...\r", len,
1425                      (*progress_buf=='\0' ? "" : progress_buf));
1426             } else {
1427                /* do not translate -- program constants */
1428                fprintf(stderr, "HTTP: %1d of %1d bytes %s...\r", len-header_len,
1429                      content_len, (*progress_buf=='\0' ? "" : progress_buf));
1430             }
1431          }
1432          if (chopped_len != (-1)) {
1433             len = chopped_len;
1434          }
1435       }
1436    } while (status == TG_REMOTE_STATUS_OK && !end_of_file);
1437 
1438    if (status == TG_REMOTE_STATUS_OK) {
1439       buf[len] = '\0';
1440       *ppsz_buf = buf;
1441       if (pn_buf_sz != NULL) *pn_buf_sz = len;
1442       sprintf(msg, TgLoadCachedString(CSTID_RESPONSES_RECEIVED), "HTTP");
1443       if ((debugHttp % 100) == 99) {
1444          /* debug, do not translate */
1445          if (!cmdLineDumpURL) {
1446             fprintf(stderr, "\n==========>>>\n");
1447             (void)fwrite(buf, sizeof(char), len, stderr);
1448             fprintf(stderr, "\n<<<==========\n");
1449          }
1450       }
1451    } else {
1452       if (buf != NULL) free(buf);
1453 
1454       if (status == TG_REMOTE_STATUS_INTR) {
1455          if (PRTGIF && cmdLineDumpURL && cmdLineDumpURLShowStatus) {
1456             fprintf(stderr, "\n");
1457          }
1458          /* should get rid of all key presses */
1459          while (ESCPressed()) ;
1460 
1461          ResetMultipartReplace(TRUE);
1462 
1463          sprintf(msg, TgLoadString(STID_CONN_ABORT_BY_USER), "HTTP");
1464       } else {
1465          sprintf(msg, TgLoadString(STID_ERROR_ENCOUNTERED_WHILE_RECV), "HTTP");
1466       }
1467    }
1468    ShowRemoteStatus(msg);
1469    if (PRTGIF && cmdLineDumpURL && cmdLineDumpURLShowStatus) {
1470       fprintf(stderr, "\n");
1471    }
1472    return status;
1473 }
1474