Diff
Not logged in

Differences From:

File src/cgi.c part of check-in [0a14f18111] - Return a proper error message if the first line of an HTTP requested handed to the "http" command is blank. by drh on 2008-05-14 12:21:23. [view]

To:

File src/cgi.c part of check-in [e2e016c31f] - Get the "server" command running under windows. by drh on 2008-05-17 17:43:22. [view]

@@ -287,17 +287,17 @@
   }
 #endif
 
   if( fullHttpReply ){
-    printf("HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
-    printf("Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
-    printf("Connection: close\r\n");
+    fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
+    fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
+    fprintf(g.httpOut, "Connection: close\r\n");
   }else{
-    printf("Status: %d %s\r\n", iReplyStatus, zReplyStatus);
+    fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
   }
 
   if( blob_size(&extraHeader)>0 ){
-    printf("%s", blob_buffer(&extraHeader));
+    fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
   }
 
   if( g.isConst ){
     /* constant means that the input URL will _never_ generate anything
@@ -309,20 +309,22 @@
     ** header set to a reasonable period (default: one week).
     */
     /*time_t expires = time(0) + atoi(db_config("constant_expires","604800"));*/
     time_t expires = time(0) + 604800;
-    printf( "Expires: %s\r\n", cgi_rfc822_datestamp(expires));
+    fprintf(g.httpOut, "Expires: %s\r\n", cgi_rfc822_datestamp(expires));
   }
 
   /* Content intended for logged in users should only be cached in
   ** the browser, not some shared location.
   */
-  printf("Cache-control: private\r\n");
+  fprintf(g.httpOut, "Cache-control: private\r\n");
 
 #if FOSSIL_I18N
-  printf( "Content-Type: %s; charset=%s\r\n", zContentType, nl_langinfo(CODESET));
+  fprintf(g.httpOut,
+     "Content-Type: %s; charset=%s\r\n", zContentType, nl_langinfo(CODESET));
 #else
-  printf( "Content-Type: %s; charset=ISO-8859-1\r\n", zContentType);
+  fprintf(g.httpOut,
+     "Content-Type: %s; charset=ISO-8859-1\r\n", zContentType);
 #endif
   if( strcmp(zContentType,"application/x-fossil")==0 ){
     cgi_combine_header_and_body();
     blob_compress(&cgiContent[0], &cgiContent[0]);
@@ -329,17 +331,17 @@
   }
 
   if( iReplyStatus != 304 ) {
     total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
-    printf( "Content-Length: %d\r\n", total_size);
-  }
-  printf("\r\n");
+    fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
+  }
+  fprintf(g.httpOut, "\r\n");
   if( total_size>0 && iReplyStatus != 304 ){
     int i, size;
     for(i=0; i<2; i++){
       size = blob_size(&cgiContent[i]);
       if( size>0 ){
-        fwrite(blob_buffer(&cgiContent[i]), 1, size, stdout);
+        fwrite(blob_buffer(&cgiContent[i]), 1, size, g.httpOut);
       }
     }
   }
   CGIDEBUG(("DONE\n"));
@@ -684,20 +686,20 @@
     if( strcmp(zType,"application/x-www-form-urlencoded")==0
          || strncmp(zType,"multipart/form-data",19)==0 ){
       z = malloc( len+1 );
       if( z==0 ) exit(1);
-      len = fread(z, 1, len, stdin);
+      len = fread(z, 1, len, g.httpIn);
       z[len] = 0;
       if( zType[0]=='a' ){
         add_param_list(z, '&');
       }else{
         process_multipart_form_data(z, len);
       }
     }else if( strcmp(zType, "application/x-fossil")==0 ){
-      blob_read_from_channel(&g.cgiIn, stdin, len);
+      blob_read_from_channel(&g.cgiIn, g.httpIn, len);
       blob_uncompress(&g.cgiIn, &g.cgiIn);
     }else if( strcmp(zType, "application/x-fossil-debug")==0 ){
-      blob_read_from_channel(&g.cgiIn, stdin, len);
+      blob_read_from_channel(&g.cgiIn, g.httpIn, len);
     }
   }
 
   z = (char*)P("HTTP_COOKIE");
@@ -1073,17 +1075,17 @@
 ** environment variables as per CGI.  The cgi_init() routine to complete
 ** the setup.  Once all the setup is finished, this procedure returns
 ** and subsequent code handles the actual generation of the webpage.
 */
-void cgi_handle_http_request(void){
+void cgi_handle_http_request(const char *zIpAddr){
   char *z, *zToken;
   int i;
   struct sockaddr_in remoteName;
   size_t size = sizeof(struct sockaddr_in);
   char zLine[2000];     /* A single line of input. */
 
   fullHttpReply = 1;
-  if( fgets(zLine, sizeof(zLine), stdin)==0 ){
+  if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
     malformed_request();
   }
   zToken = extract_token(zLine, &z);
   if( zToken==0 ){
@@ -1103,22 +1105,22 @@
   for(i=0; zToken[i] && zToken[i]!='?'; i++){}
   if( zToken[i] ) zToken[i++] = 0;
   cgi_setenv("PATH_INFO", zToken);
   cgi_setenv("QUERY_STRING", &zToken[i]);
-  if( getpeername(fileno(stdin), (struct sockaddr*)&remoteName, (socklen_t*)&size)>=0 ){
-    char *zIpAddr = inet_ntoa(remoteName.sin_addr);
-    cgi_setenv("REMOTE_ADDR", zIpAddr);
-
-    /* Set the Global.zIpAddr variable to the server we are talking to.
-    ** This is used to populate the ipaddr column of the rcvfrom table,
-    ** if any files are received from the connected client.
-    */
+  if( zIpAddr==0 &&
+        getpeername(fileno(g.httpIn), (struct sockaddr*)&remoteName,
+                                (socklen_t*)&size)>=0
+  ){
+    zIpAddr = inet_ntoa(remoteName.sin_addr);
+  }
+  if( zIpAddr ){
+    cgi_setenv("REMOTE_ADDR", zIpAddr);
     g.zIpAddr = mprintf("%s", zIpAddr);
   }
 
   /* Get all the optional fields that follow the first line.
   */
-  while( fgets(zLine,sizeof(zLine),stdin) ){
+  while( fgets(zLine,sizeof(zLine),g.httpIn) ){
     char *zFieldName;
     char *zVal;
 
     zFieldName = extract_token(zLine,&zVal);
@@ -1161,10 +1163,13 @@
 **
 ** As new connections arrive, fork a child and let child return
 ** out of this procedure call.  The child will handle the request.
 ** The parent never returns from this procedure.
+**
+** Return 0 to each child as it runs.  If unable to establish a
+** listening socket, return non-zero.
 */
-void cgi_http_server(int iPort){
+int cgi_http_server(int iPort){
 #ifdef __MINGW32__
   fprintf(stderr,"server not yet available in windows version of fossil\n");
   exit(1);
 #else
@@ -1183,18 +1188,17 @@
   inaddr.sin_addr.s_addr = INADDR_ANY;
   inaddr.sin_port = htons(iPort);
   listener = socket(AF_INET, SOCK_STREAM, 0);
   if( listener<0 ){
-    fprintf(stderr,"Can't create a socket\n");
-    exit(1);
+    return 1;
   }
 
   /* if we can't terminate nicely, at least allow the socket to be reused */
   setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
 
   if( bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr))<0 ){
-    fprintf(stderr,"Can't bind to port %d\n", iPort);
-    exit(1);
+    close(listener);
+    return 1;
   }
   listen(listener,10);
   while( 1 ){
     if( nchildren>MAX_PARALLEL ){
@@ -1206,9 +1210,10 @@
     FD_ZERO(&readfds);
     FD_SET( listener, &readfds);
     if( select( listener+1, &readfds, 0, 0, &delay) ){
       lenaddr = sizeof(inaddr);
-      connection = accept(listener, (struct sockaddr*)&inaddr, (socklen_t*) &lenaddr);
+      connection = accept(listener, (struct sockaddr*)&inaddr,
+                                    (socklen_t*) &lenaddr);
       if( connection>=0 ){
         child = fork();
         if( child!=0 ){
           if( child>0 ) nchildren++;
@@ -1222,9 +1227,9 @@
             close(2);
             dup(connection);
           }
           close(connection);
-          return;
+          return 0;
         }
       }
     }
     /* Bury dead children */
@@ -1235,8 +1240,9 @@
   /* NOT REACHED */
   exit(1);
 #endif
 }
+
 
 /*
 ** Name of days and months.
 */