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 */