Attachment Details
Not logged in
Overview

Artifact ID: fd4ce405db3bbd77ab59f1da2870c63a79ea8337
Ticket: 11622724e5b46818396db583ac839391f70c8d64
Date: 2010-08-26 09:54:59
User: anonymous
Artifact Attached: f938e4d31690b5b0aad8eeca5f4733c795445d6b
Filename:winhttp.c
Description:winhttp.c
Content Appended
     1  /*
     2  ** Copyright (c) 2008 D. Richard Hipp
     3  **
     4  ** This program is free software; you can redistribute it and/or
     5  ** modify it under the terms of the Simplified BSD License (also
     6  ** known as the "2-Clause License" or "FreeBSD License".)
     7  
     8  ** This program is distributed in the hope that it will be useful,
     9  ** but without any warranty; without even the implied warranty of
    10  ** merchantability or fitness for a particular purpose.
    11  **
    12  ** Author contact information:
    13  **   drh@hwaci.com
    14  **   http://www.hwaci.com/drh/
    15  **
    16  *******************************************************************************
    17  **
    18  ** This file implements a very simple (and low-performance) HTTP server
    19  ** for windows.
    20  */
    21  #ifdef __MINGW32__           /* This code is for win32 only */
    22  #include "config.h"
    23  #include "winhttp.h"
    24  #include <windows.h>
    25  
    26  #include "my_popen.h"
    27  
    28  
    29  /*
    30  ** The HttpRequest structure holds information about each incoming
    31  ** HTTP request.
    32  */
    33  typedef struct HttpRequest HttpRequest;
    34  struct HttpRequest {
    35    int id;             /* ID counter */
    36    SOCKET s;           /* Socket on which to receive data */
    37    SOCKADDR_IN addr;   /* Address from which data is coming */
    38    const char *zNotFound;  /* --notfound option, or an empty string */
    39  };
    40  
    41  /*
    42  ** Prefix for a temporary file.
    43  */
    44  static char *zTempPrefix;
    45  
    46  /*
    47  ** Look at the HTTP header contained in zHdr.  Find the content
    48  ** length and return it.  Return 0 if there is no Content-Length:
    49  ** header line.
    50  */
    51  static int find_content_length(const char *zHdr){
    52    while( *zHdr ){
    53      if( zHdr[0]=='\n' ){
    54        if( zHdr[1]=='\r' ) return 0;
    55        if( strncasecmp(&zHdr[1], "content-length:", 15)==0 ){
    56          return atoi(&zHdr[17]);
    57        }
    58      }
    59      zHdr++;
    60    }
    61    return 0;
    62  }
    63  
    64  /*
    65  ** Process a single incoming HTTP request.
    66  */
    67  void win32_process_one_http_request(void *pAppData){
    68    HttpRequest *p = (HttpRequest*)pAppData;
    69    FILE *in = 0, *out = 0;
    70    int amt, got;
    71    int wanted = 0;
    72    char *z;
    73    char zRequestFName[100];
    74    char zReplyFName[100];
    75    char zCmd[2000];          /* Command-line to process the request */
    76    char zHdr[2000];          /* The HTTP request header */
    77  
    78    sprintf(zRequestFName, "%s_in%d.txt", zTempPrefix, p->id);
    79    sprintf(zReplyFName, "%s_out%d.txt", zTempPrefix, p->id);
    80  #if defined(FOSSIL_CHILD_DEBUG)
    81    //sprintf(zCmd, "sh -c '\"%s\" http \"%s\" --httptrace | tee abc'", g.argv[0], g.zRepositoryName);
    82    sprintf(zCmd, "\"%s\" http \"%s\" --httptrace ", g.argv[0], g.zRepositoryName);
    83  #else
    84    sprintf(zCmd, "\"%s\" http \"%s\" ", g.argv[0], g.zRepositoryName);
    85  #endif
    86  
    87    int childPid;
    88    popen2(zCmd, &in, &out, &childPid);
    89  
    90    amt = 0;
    91    while( amt<sizeof(zHdr) ){
    92      got = recv(p->s, &zHdr[amt], sizeof(zHdr)-1-amt, 0);
    93      if( got==SOCKET_ERROR ) goto end_request;
    94      if( got==0 ){
    95        wanted = 0;
    96        break;
    97      }
    98      amt += got;
    99      zHdr[amt] = 0;
   100      z = strstr(zHdr, "\r\n\r\n");
   101      if( z ){
   102        wanted = find_content_length(zHdr) + (&z[4]-zHdr) - amt;
   103        break;
   104      }
   105    }
   106    if( amt>=sizeof(zHdr) ) goto end_request;
   107    //out = fopen(zRequestFName, "wb");
   108    if( out==0 ) goto end_request;
   109    fwrite(zHdr, 1, amt, out);
   110    while( wanted>0 ){
   111      got = recv(p->s, zHdr, sizeof(zHdr), 0);
   112      if( got==SOCKET_ERROR ) goto end_request;
   113      if( got ){
   114        fwrite(zHdr, 1, got, out);
   115      }else{
   116        break;
   117      }
   118      wanted -= got;
   119    }
   120    fclose(out);
   121    out = 0;
   122    //sprintf(zCmd, "\"%s\" http \"%s\" %s %s %s%s",
   123    //  g.argv[0], g.zRepositoryName, zRequestFName, zReplyFName, 
   124    //  inet_ntoa(p->addr.sin_addr), p->zNotFound
   125    //);
   126    //portable_system(zCmd);
   127    //in = fopen(zReplyFName, "rb");
   128    if( in ){
   129      while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){
   130        send(p->s, zHdr, got, 0);
   131      }
   132    }
   133  
   134  end_request:
   135    if( out ) fclose(out);
   136    if( in ) fclose(in);
   137    closesocket(p->s);
   138    unlink(zRequestFName);
   139    unlink(zReplyFName);
   140    free(p);
   141  }
   142  
   143  /*
   144  ** Start a listening socket and process incoming HTTP requests on
   145  ** that socket.
   146  */
   147  void win32_http_server(
   148    int mnPort, int mxPort,   /* Range of allowed TCP port numbers */
   149    const char *zBrowser,     /* Command to launch browser.  (Or NULL) */
   150    const char *zStopper,     /* Stop server when this file is exists (Or NULL) */
   151    const char *zNotFound     /* The --notfound option, or NULL */
   152  ){
   153    WSADATA wd;
   154    SOCKET s = INVALID_SOCKET;
   155    SOCKADDR_IN addr;
   156    int idCnt = 0;
   157    int iPort = mnPort;
   158    char *zNotFoundOption;
   159  
   160    if( zStopper ) unlink(zStopper);
   161    if( zNotFound ){
   162      zNotFoundOption = mprintf(" --notfound %s", zNotFound);
   163    }else{
   164      zNotFoundOption = "";
   165    }
   166    if( WSAStartup(MAKEWORD(1,1), &wd) ){
   167      fossil_fatal("unable to initialize winsock");
   168    }
   169    while( iPort<=mxPort ){
   170      s = socket(AF_INET, SOCK_STREAM, 0);
   171      if( s==INVALID_SOCKET ){
   172        fossil_fatal("unable to create a socket");
   173      }
   174      addr.sin_family = AF_INET;
   175      addr.sin_port = htons(iPort);
   176      addr.sin_addr.s_addr = htonl(INADDR_ANY);
   177      if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){
   178        closesocket(s);
   179        iPort++;
   180        continue;
   181      }
   182      if( listen(s, SOMAXCONN)==SOCKET_ERROR ){
   183        closesocket(s);
   184        iPort++;
   185        continue;
   186      }
   187      break;
   188    }
   189    if( iPort>mxPort ){
   190      if( mnPort==mxPort ){
   191        fossil_fatal("unable to open listening socket on ports %d", mnPort);
   192      }else{
   193        fossil_fatal("unable to open listening socket on any"
   194                     " port in the range %d..%d", mnPort, mxPort);
   195      }
   196    }
   197    zTempPrefix = mprintf("fossil_server_P%d_", iPort);
   198    printf("Listening for HTTP requests on TCP port %d\n", iPort);
   199    if( zBrowser ){
   200      zBrowser = mprintf(zBrowser, iPort);
   201      printf("Launch webbrowser: %s\n", zBrowser);
   202      portable_system(zBrowser);
   203    }
   204    printf("Type Ctrl-C to stop the HTTP server\n");
   205    for(;;){
   206      SOCKET client;
   207      SOCKADDR_IN client_addr;
   208      HttpRequest *p;
   209      int len = sizeof(client_addr);
   210  
   211      client = accept(s, (struct sockaddr*)&client_addr, &len);
   212      if( zStopper && file_size(zStopper)>=0 ){
   213        break;
   214      }
   215      if( client==INVALID_SOCKET ){
   216        closesocket(s);
   217        fossil_fatal("error from accept()");
   218      }
   219      p = malloc( sizeof(*p) );
   220      if( p==0 ){
   221        fossil_fatal("out of memory");
   222      }
   223      p->id = ++idCnt;
   224      p->s = client;
   225      p->addr = client_addr;
   226      p->zNotFound = zNotFoundOption;
   227      _beginthread(win32_process_one_http_request, 0, (void*)p);
   228    }
   229    closesocket(s);
   230    WSACleanup();
   231  }
   232  
   233  #endif /* __MINGW32__  -- This code is for win32 only */