earlybrowserreborn - Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 roytam 1 /*
2  *  These are the WWW - Midas Interface routines
3  */
4  
5  
6  
7 #include "midasnet.h"
8  
9 #include <string.h>
10  
11 extern XtAppContext appl_context;
12 extern XrmQuark fileDestination;
13 extern XrmQuark htmlDestination;
14 extern XrmQuark textDestination;
15 extern XrmQuark psDestination;
16 extern XrmQuark gifDestination;
17 extern XrmQuark xbmDestination;
18 extern XrmQuark unsupportDestination;
19  
20 #define DEADNODE ((WWWNode *) -1)
21 extern WWWNode *WWWFromLink;
22 extern char password[64];
23 extern void ClearFlag();
24  
25 extern char *WWWAsciiFile();
26 void WWWAddReadInputEvent();
27 static int WWWUseHTTPVersion1();
28  
29 static char *htrq = NULL;
30  
31 char *WWWGetHTRQ()
32 {
33   int size = 512;
34   char *accept = "Accept: ";
35   char *accept_encode = "Accept-Encoding: ";
36   char *from = "From: ";
37   char useragent[100];
38   char *header = XtMalloc(size);
39   ListItem *i = appResources.mimetypes->First;
40   ListItem *j = appResources.mimeencode->First;
41   ListItem *k = appResources.usermimetypes->First;
42   ListItem *l = appResources.usermimeencode->First;
43  
44   sprintf(useragent,"User-Agent: MidasWWW/%s\r\n",VERSION);
45  
46   *header = '\0';
47   for (; i ; i = i->Next)
48     {
49        if (strlen(header) > size - 128)
50          header = XtRealloc(header, size += 128);
51        strcat(header,accept);
52        strcat(header,i->Entry);
53        strcat(header,"\r\n");
54      }
55   for (;k ; k = k->Next)
56     {
57       if (MidasFindItemInList(appResources.mimetypes,k->Entry)) continue;
58       if (strlen(header) > size - 128)
59          header = XtRealloc(header, size += 128);
60        strcat(header,accept);
61        strcat(header,k->Entry);
62        strcat(header,"\r\n");
63     }
64   for(; j ; j = j->Next)
65     {
66        if (strlen(header) > size - 128)
67          header = XtRealloc(header, size += 128);
68        strcat(header,accept_encode);
69        strcat(header,j->Entry);
70        strcat(header,"\r\n");
71      }
72   for (;l ; l = l->Next)
73     {
74       if (MidasFindItemInList(appResources.mimeencode,l->Entry)) continue;
75       if (strlen(header) > size - 128)
76          header = XtRealloc(header, size += 128);
77        strcat(header,accept_encode);
78        strcat(header,l->Entry);
79        strcat(header,"\r\n");
80     }
81  
82   header = XtRealloc(header, size += 128);
83   strcat(header,from);
84   strcat(header,password);
85   strcat(header,"\r\n");
86   strcat(header,useragent);
87   return header;
88 }
89  
90 Widget WWWPostDocumentHTTP1(w,file,mb)
91 Widget        w;
92 WWWFile      *file;
93 MessageBlock *mb;
94 {
95   char *command, *copy, name[128];
96   Widget result = NULL;
97   DataSource data;
98   int s, http1 = -1, fd = 0;
99   WWWFiletype *filetype = NULL;  
100   char *tmpf;
101   char *referer, post[256];
102   ListItem *item;
103   char buffer[8096];
104   char *idata = XrmQuarkToString(file->keyword);
105  
106   if (file->node == NULL)
107     {
108       strcat(mb->message,"No node specified for HTTP connection");
109       mb->help_code = "http_no_node";
110       return NULL;
111     }  
112   if (file->port == 0) file->port = appResources.default_HTTP_port;
113  
114   s = TCPIPConnect(file,mb);
115   if (s == 0) return result;
116  
117   /* use static so that we don't need to waste time to get it each time */
118  
119   if (htrq == NULL) htrq = WWWGetHTRQ();
120  
121   if (WWWFromLink != DEADNODE && WWWFromLink != NULL)
122     {
123       char *fromurl;
124       char *refer = "Referer: ";
125       fromurl = WWWAsciiFile(WWWFromLink->file);
126       referer = XtMalloc(strlen(fromurl)+30);
127       strcpy(referer,refer);
128       strcat(referer,fromurl);
129       strcat(referer,"\r\n");
130       XtFree(fromurl);
131     }
132   else referer = NULL;
133  
134   sprintf(post,"Content-type: application/x-www-form-urlencoded\r\nContent-length: %d\r\n\r\n",strlen(idata));
135  
136   command = XtMalloc(30 + strlen(htrq) + strlen(referer) + strlen(post) + (file->file ? strlen(XrmQuarkToString(file->file)) : 0));
137  
138   strcpy(command,"POST ");
139   strcat(command,file->file ? XrmQuarkToString(file->file): "/");
140   strcat(command," HTTP/1.0\r\n");
141  
142   strcat(command, htrq);
143   if (referer)
144     {
145       strcat(command,referer);
146       XtFree(referer);
147     }
148   strcat(command,post);
149  
150   if (!TCPIPWriteAndWaitForResponse(s,file,mb,command)) goto cleanup;
151   XtFree(command);
152  
153   if (!TCPIPWriteAndWaitForResponse(s,file,mb,idata)) goto cleanup;
154  
155   WWWInitDataSource(&data,mb,buffer,sizeof(buffer),socket_read,s);
156  
157   http1 = WWWUseHTTPVersion1(&data,filetype,mb,name);
158   if (mb->flag == 1) goto cleanup;
159  
160   data.read = 0; /* Some (bad) Load routines expect this */
161  
162   if (http1 == 1)
163     {
164       filetype = WWWGetFiletype(name,appResources.httpDefaultFiletype);
165  
166       if (filetype->Destination == fileDestination)
167         {
168           /* First we need to ask the user where he wants to save this thing??
169            */
170           int managed = 0;
171  
172           copy = strrchr(XrmQuarkToString(file->file), '/');
173           if (copy) copy = XtNewString(copy+1);
174           else      copy = XtNewString(XrmQuarkToString(file->file));
175  
176           if (copy && filetype->Filter)
177             {
178               char *ext = strrchr(copy,'.');
179               if (ext) *ext = '\0';
180              }
181           filetype->UserData = copy;
182  
183           /* In case the time asking the user for file destination is  */
184           /* longer than the time socket buffer is filled up, therefore */
185           /* we write data to temp file and then re-load it back.       */
186  
187           if (!WWWWriteToTempfile(mb,GetCharacter,&data,&tmpf,".tar")) goto cleanup;
188           if ((fd = open(tmpf,O_RDONLY,0)) < 0)
189             {
190               sprintf(mb->message,"Cannot open file <p>Reason: %s",strerror(errno));
191               mb->help_code = "file_open_failed";
192               goto cleanup;
193             }
194           data.socket = fd;
195  
196           *mb->message = '\0';
197           if (managed = XtIsManaged(mb->widget)) XtUnmanageChild(mb->widget);
198           if (!WWWAskForFileDestination(w,mb,filetype,FALSE)) goto cleanup;
199           if (managed) XtManageChild(mb->widget);  
200         }
201     }
202   else  /* http1 < 0 : either the client error or server error */
203     {
204       if (http1 == 0)
205         {
206           strcat(mb->message,"Bad HTTP response from POST command");
207           mb->help_code = "http_bad_post";
208         }
209       goto cleanup;
210     }
211  
212   result = WWWLoadByFiletype(w,mb,filetype,GetCharacter,&data);
213  
214 cleanup:
215  
216   if (filetype) WWWFreeFiletype(filetype);
217   if (s) socket_close(s);
218   if (fd)
219     {
220       unlink(tmpf);
221       XtFree(tmpf);
222     }
223   return result;
224 }
225 /*
226  * Fetch the document using TCP/IP and HTTP
227  * ----------------------------------------
228  */
229 Widget WWWFetchDocumentHTTP1(w,file,mb)
230 Widget w;
231 WWWFile *file;
232 MessageBlock *mb;
233 {
234   char *command, *copy, name[128];
235   Widget result = NULL;
236   DataSource data;
237   int s, http1 = -1, fd = 0;
238   WWWFiletype *filetype = NULL;  
239   char *tmpf;
240   char referer[256];
241   ListItem *item;
242   static List *http0List = NULL;
243   char buffer[8096];
244  
245   if (file->node == NULL)
246     {
247       strcat(mb->message,"No node specified for HTTP connection");
248       mb->help_code = "http_no_node";
249       return NULL;
250     }  
251   if (file->port == 0) file->port = appResources.default_HTTP_port;
252  
253   if (http0List)
254     {
255       sprintf(name,"%s:%d",XrmQuarkToString(file->node),file->port);
256       item = MidasFindItemInList(http0List,name);
257       if (item) return WWWFetchDocumentHTTP(w,file,mb);
258     }
259  
260   s = TCPIPConnect(file,mb);
261   if (s == 0) return result;
262  
263   /* use static so that we don't need to waste time to get it each time */
264   if (htrq == NULL) htrq = WWWGetHTRQ();
265  
266   if (WWWFromLink != DEADNODE && WWWFromLink != NULL)
267     {
268       char *fromurl;
269       char *refer = "Referer: ";
270       fromurl = WWWAsciiFile(WWWFromLink->file);
271       strcpy(referer,refer);
272       strcat(referer,fromurl);
273       strcat(referer,"\r\n\r\n");
274       XtFree(fromurl);
275     }
276   else *referer = '\0';
277  
278   command = XtMalloc(20 + strlen(htrq) + strlen(referer) + (file->file ? strlen(XrmQuarkToString(file->file)) : 0));
279  
280   strcpy(command,"GET ");
281   strcat(command,file->file ? XrmQuarkToString(file->file): "/");
282   strcat(command," HTTP/1.0\r\n");
283  
284   strcat(command, htrq);
285   if (*referer)
286     strcat(command,referer);
287   else
288     strcat(command,"\r\n");
289  
290   if (!TCPIPWriteAndWaitForResponse(s,file,mb,command)) goto cleanup;
291   XtFree(command);
292  
293   WWWInitDataSource(&data,mb,buffer,sizeof(buffer),socket_read,s);
294  
295   http1 = WWWUseHTTPVersion1(&data,filetype,mb,name);
296   if (mb->flag == 1) goto cleanup;
297  
298   data.read = 0; /* Some (bad) Load routines expect this */
299  
300   if (http1 == 1)
301     {
302       filetype = WWWGetFiletype(name,appResources.httpDefaultFiletype);
303  
304       if (filetype->Destination == fileDestination)
305         {
306           /* First we need to ask the user where he wants to save this thing??
307            */
308           int managed = 0;
309  
310           copy = strrchr(XrmQuarkToString(file->file), '/');
311           if (copy) copy = XtNewString(copy+1);
312           else      copy = XtNewString(XrmQuarkToString(file->file));
313  
314           if (copy && filetype->Filter)
315             {
316               char *ext = strrchr(copy,'.');
317               if (ext) *ext = '\0';
318              }
319           filetype->UserData = copy;
320  
321           /* In case the time asking the user for file destination is  */
322           /* longer than the time socket buffer is filled up, therefore */
323           /* we write data to temp file and then re-load it back.       */
324  
325           if (!WWWWriteToTempfile(mb,GetCharacter,&data,&tmpf,".tar")) goto cleanup;
326           if ((fd = open(tmpf,O_RDONLY,0)) < 0)
327             {
328               sprintf(mb->message,"Cannot open file <p>Reason: %s",strerror(errno));
329               mb->help_code = "file_open_failed";
330               goto cleanup;
331             }
332           data.socket = fd;
333  
334           *mb->message = '\0';
335           if (managed = XtIsManaged(mb->widget)) XtUnmanageChild(mb->widget);
336           if (!WWWAskForFileDestination(w,mb,filetype,FALSE)) goto cleanup;
337           if (managed) XtManageChild(mb->widget);  
338         }
339     }
340   else if (http1 == 0)
341     {
342       /* if the server does not understand HTTP/1.0, then use HTTP/0.9 */
343       /*
344        * Experience shows that if the server fails to identify itself as
345        * HTTP/1.0 compatible, then best course of action is to close the
346        * socket and try again with HTTP/0.9 (otherwise various problems can arise).
347        *
348        * We cache the names of such servers so that future connections can use
349        * HTTP/0.9 immediately.
350        */
351  
352       socket_close(s);
353  
354       if (!http0List) http0List = MidasCreateEmptyList("http0List");
355       sprintf(name,"%s:%d",XrmQuarkToString(file->node),file->port);
356       MidasAddItemToList(http0List,name);
357  
358       return WWWFetchDocumentHTTP(w,file,mb);
359     }
360   else  /* http1 < 0 : either the client error or server error */
361     {
362       goto cleanup;
363     }
364  
365   result = WWWLoadByFiletype(w,mb,filetype,GetCharacter,&data);
366  
367 cleanup:
368  
369   if (filetype) WWWFreeFiletype(filetype);
370   if (s) socket_close(s);
371   if (fd)
372     {
373       unlink(tmpf);
374       XtFree(tmpf);
375     }
376   return result;
377 }  
378 static int WWWUseHTTPVersion1(data,filetype,mb,ext)
379 DataSource *data;
380 WWWFiletype *filetype;
381 MessageBlock *mb;
382 char *ext;
383 {
384   int save, i, n;
385   char response[256], c_type[256], c_encode[256], location[256], error[256];
386   char pheader[10];
387   char *copy;
388   float level = 0.0;
389   int rcode = 200;
390  
391   /*
392    * Note: We cannot allow GetCharacter to buffer characters
393    *       internally, thus causing problems if the stream has to be
394    *       subsequently passed to a forked process that does not use
395    *       GetCharacter
396    */
397  
398   save = data->bsize;
399   data->bsize = 1;
400  
401   for (i = 0; i < 8; i++) pheader[i] = GetCharacter(data);
402   if (data->eof) goto fail;
403  
404   data->mb->newMessage = TRUE;
405   strcpy(data->mb->message,"Reading HTTP header");
406  
407   sscanf(pheader, "HTTP/%f", &level);
408   if (level < 0.99) goto fail;
409  
410   c_type[0] = c_encode[0] = '\0';
411  
412   for (n = i = 0; ; )
413     {
414       char c = response[i++] = GetCharacter(data);
415       if (data->eof)
416         {
417           if (rcode/100 == 2) /* if things were ok , they are not now! */
418             {
419               rcode = 999;
420             }
421           break;
422         }
423       else if (c == '\n' || i > 253)  /* read a line each time */
424         {
425           response[i] = '\0';
426           if (n == 0)
427             {
428               sscanf(response,"%d",&rcode);
429               strcpy(error,response);
430             }          
431           else
432             {
433               char *token = strtok(response,":");
434  
435               if (strlen(response) < 3) break;
436               else if (!strcasecmp(token,"encoding"))
437                 strcpy(c_encode,strtok(NULL," \r\n"));
438               else if (!strcasecmp(response,"content-type"))
439                 strcpy(c_type,strtok(NULL," \r\n"));
440               else if (!strcasecmp(response,"location"))
441                 strcpy(location,strtok(NULL," \r\n"));
442               else if (!strcasecmp(response,"content-length"))
443                 sscanf(strtok(NULL," \r\n"),"%d",&data->length);
444             }  
445           i = 0;
446           n++;
447         }
448     }
449  
450   strcpy(ext,"http1.");
451   copy = strrchr(c_type,'/');
452   if (copy) strcat(ext,copy+1);
453   if (*c_encode)
454     {
455       strcat(ext,".");
456       strcat(ext,c_encode);
457     }
458   data->bsize = save;
459   if (rcode == 301 || rcode == 302)
460     {
461       sprintf(mb->message,"<h1>Moved</h1>Document has moved <a href=\"%s\" redirect=true>here</a>.",location);
462       return -rcode;
463     }
464   else if (rcode == 999)
465     {
466       sprintf(mb->message,"Error reading document header.");
467       mb->help_code = "header_error";      
468       return -rcode;
469     }
470   else if (rcode/100 != 2)
471     {
472       mb->help_code = "request_error";
473       sprintf(mb->message,"Document fetch failed.<p>Reason: %s",error);
474       return -rcode;
475     }  
476   return 1;
477  
478 fail:
479  
480   data->bsize = save;
481   return 0;  
482 }