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