test1509: verify proxy header response headers count
Modified sws to support and use custom CONNECT responses instead of the previously naive hard-coded version. Made the HTTP test server able to extract test case number from the host name in a CONNECT request by finding the number after the last dot. It makes 'machine.moo.123' use test case 123. Adapted a larger amount of tests to the new <connect> style. Bug: http://curl.haxx.se/bug/view.cgi?id=1204 Reported by: Martin Jansen
This commit is contained in:
@@ -88,6 +88,8 @@ static bool prevbounce=FALSE; /* instructs the server to increase the part
|
||||
|
||||
struct httprequest {
|
||||
char reqbuf[REQBUFSIZ]; /* buffer area for the incoming request */
|
||||
bool connect_request; /* if a CONNECT */
|
||||
unsigned short connect_port; /* the port number CONNECT used */
|
||||
size_t checkindex; /* where to start checking of the request */
|
||||
size_t offset; /* size of the incoming request */
|
||||
long testno; /* test number found in the request */
|
||||
@@ -111,7 +113,6 @@ struct httprequest {
|
||||
int prot_version; /* HTTP version * 10 */
|
||||
bool pipelining; /* true if request is pipelined */
|
||||
int callcount; /* times ProcessRequest() gets called */
|
||||
unsigned short connect_port; /* the port number CONNECT used */
|
||||
bool connmon; /* monitor the state of the connection, log disconnects */
|
||||
int done_processing;
|
||||
};
|
||||
@@ -166,11 +167,8 @@ const char *serverlogfile = DEFAULT_LOGFILE;
|
||||
#define END_OF_HEADERS "\r\n\r\n"
|
||||
|
||||
enum {
|
||||
DOCNUMBER_NOTHING = -7,
|
||||
DOCNUMBER_QUIT = -6,
|
||||
DOCNUMBER_BADCONNECT = -5,
|
||||
DOCNUMBER_INTERNAL= -4,
|
||||
DOCNUMBER_CONNECT = -3,
|
||||
DOCNUMBER_NOTHING = -4,
|
||||
DOCNUMBER_QUIT = -3,
|
||||
DOCNUMBER_WERULEZ = -2,
|
||||
DOCNUMBER_404 = -1
|
||||
};
|
||||
@@ -181,14 +179,6 @@ static const char *end_of_headers = END_OF_HEADERS;
|
||||
static const char *docquit =
|
||||
"HTTP/1.1 200 Goodbye" END_OF_HEADERS;
|
||||
|
||||
/* sent as reply to a CONNECT */
|
||||
static const char *docconnect =
|
||||
"HTTP/1.1 200 Mighty fine indeed" END_OF_HEADERS;
|
||||
|
||||
/* sent as reply to a "bad" CONNECT */
|
||||
static const char *docbadconnect =
|
||||
"HTTP/1.1 501 Forbidden you fool" END_OF_HEADERS;
|
||||
|
||||
/* send back this on 404 file not found */
|
||||
static const char *doc404 = "HTTP/1.1 404 Not Found\r\n"
|
||||
"Server: " SWSVERSION "\r\n"
|
||||
@@ -342,8 +332,8 @@ static int parse_servercmd(struct httprequest *req)
|
||||
if(!stream) {
|
||||
error = errno;
|
||||
logmsg("fopen() failed with error: %d %s", error, strerror(error));
|
||||
logmsg("Error opening file: %s", filename);
|
||||
logmsg("Couldn't open test file %ld", req->testno);
|
||||
logmsg(" [1] Error opening file: %s", filename);
|
||||
logmsg(" Couldn't open test file %ld", req->testno);
|
||||
req->open = FALSE; /* closes connection */
|
||||
return 1; /* done */
|
||||
}
|
||||
@@ -533,6 +523,8 @@ static int ProcessRequest(struct httprequest *req)
|
||||
doc, prot_major, prot_minor);
|
||||
logmsg("%s", logbuf);
|
||||
|
||||
req->connect_request = TRUE;
|
||||
|
||||
if(req->prot_version == 10)
|
||||
req->open = FALSE; /* HTTP 1.0 closes connection by default */
|
||||
|
||||
@@ -557,55 +549,45 @@ static int ProcessRequest(struct httprequest *req)
|
||||
else
|
||||
req->connect_port = curlx_ultous(ulnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!strncmp(doc, "bad", 3))
|
||||
/* if the host name starts with bad, we fake an error here */
|
||||
req->testno = DOCNUMBER_BADCONNECT;
|
||||
else if(!strncmp(doc, "test", 4))
|
||||
/* if the host name starts with test, the port number used in the
|
||||
CONNECT line will be used as test number! */
|
||||
req->testno = req->connect_port?req->connect_port:DOCNUMBER_CONNECT;
|
||||
if(req->testno == DOCNUMBER_NOTHING) {
|
||||
/* Still no test case number. Try to get the the number off the last dot
|
||||
instead, IE we consider the TLD to be the test number. Test 123 can
|
||||
then be written as "example.com.123". */
|
||||
|
||||
/* find the last dot */
|
||||
ptr = strrchr(doc, '.');
|
||||
|
||||
/* get the number after it */
|
||||
if(ptr) {
|
||||
ptr++; /* skip the dot */
|
||||
|
||||
req->testno = strtol(ptr, &ptr, 10);
|
||||
|
||||
if(req->testno > 10000) {
|
||||
req->partno = req->testno % 10000;
|
||||
req->testno /= 10000;
|
||||
|
||||
logmsg("found test %d in requested host name", req->testno);
|
||||
|
||||
}
|
||||
else
|
||||
req->testno = req->connect_port?DOCNUMBER_CONNECT:DOCNUMBER_BADCONNECT;
|
||||
req->partno = 0;
|
||||
|
||||
/* find and parse <servercmd> for this test */
|
||||
sprintf(logbuf, "Requested test number %ld part %ld (from host name)",
|
||||
req->testno, req->partno);
|
||||
logmsg("%s", logbuf);
|
||||
|
||||
}
|
||||
|
||||
if(!req->testno) {
|
||||
logmsg("Did not find test number in PATH");
|
||||
req->testno = DOCNUMBER_404;
|
||||
}
|
||||
else
|
||||
parse_servercmd(req);
|
||||
}
|
||||
else {
|
||||
/* there was no trailing slash and it wasn't CONNECT, then we get the
|
||||
the number off the last dot instead, IE we consider the TLD to be
|
||||
the test number. Test 123 can then be written as
|
||||
"example.com.123". */
|
||||
|
||||
/* find the last dot */
|
||||
ptr = strrchr(doc, '.');
|
||||
|
||||
/* get the number after it */
|
||||
if(ptr) {
|
||||
ptr++; /* skip the dot */
|
||||
|
||||
req->testno = strtol(ptr, &ptr, 10);
|
||||
|
||||
if(req->testno > 10000) {
|
||||
req->partno = req->testno % 10000;
|
||||
req->testno /= 10000;
|
||||
}
|
||||
else
|
||||
req->partno = 0;
|
||||
|
||||
sprintf(logbuf, "Requested test number %ld part %ld (from host name)",
|
||||
req->testno, req->partno);
|
||||
logmsg("%s", logbuf);
|
||||
|
||||
}
|
||||
|
||||
if(!req->testno) {
|
||||
logmsg("Did not find test number in PATH");
|
||||
req->testno = DOCNUMBER_404;
|
||||
}
|
||||
else
|
||||
parse_servercmd(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if((req->offset >= 3) && (req->testno == DOCNUMBER_NOTHING)) {
|
||||
@@ -822,7 +804,7 @@ static void storerequest(char *reqbuf, size_t totalsize)
|
||||
dump = fopen(dumpfile, "ab");
|
||||
} while ((dump == NULL) && ((error = errno) == EINTR));
|
||||
if (dump == NULL) {
|
||||
logmsg("Error opening file %s error: %d %s",
|
||||
logmsg("[2] Error opening file %s error: %d %s",
|
||||
dumpfile, error, strerror(error));
|
||||
logmsg("Failed to write request input ");
|
||||
return;
|
||||
@@ -868,6 +850,7 @@ static void init_httprequest(struct httprequest *req)
|
||||
}
|
||||
req->testno = DOCNUMBER_NOTHING;
|
||||
req->partno = 0;
|
||||
req->connect_request = FALSE;
|
||||
req->open = TRUE;
|
||||
req->auth_req = FALSE;
|
||||
req->auth = FALSE;
|
||||
@@ -1007,10 +990,6 @@ static int send_doc(curl_socket_t sock, struct httprequest *req)
|
||||
const char *responsedump = is_proxy?RESPONSE_PROXY_DUMP:RESPONSE_DUMP;
|
||||
static char weare[256];
|
||||
|
||||
char partbuf[80]="data";
|
||||
|
||||
logmsg("Send response test%ld section <data%ld>", req->testno, req->partno);
|
||||
|
||||
switch(req->rcmd) {
|
||||
default:
|
||||
case RCMD_NORMALREQ:
|
||||
@@ -1056,17 +1035,6 @@ static int send_doc(curl_socket_t sock, struct httprequest *req)
|
||||
msglen, msgbuf);
|
||||
buffer = weare;
|
||||
break;
|
||||
case DOCNUMBER_INTERNAL:
|
||||
logmsg("Bailing out due to internal error");
|
||||
return -1;
|
||||
case DOCNUMBER_CONNECT:
|
||||
logmsg("Replying to CONNECT");
|
||||
buffer = docconnect;
|
||||
break;
|
||||
case DOCNUMBER_BADCONNECT:
|
||||
logmsg("Replying to a bad CONNECT");
|
||||
buffer = docbadconnect;
|
||||
break;
|
||||
case DOCNUMBER_404:
|
||||
default:
|
||||
logmsg("Replying to with a 404");
|
||||
@@ -1077,17 +1045,25 @@ static int send_doc(curl_socket_t sock, struct httprequest *req)
|
||||
count = strlen(buffer);
|
||||
}
|
||||
else {
|
||||
char partbuf[80];
|
||||
char *filename = test2file(req->testno);
|
||||
|
||||
if(0 != req->partno)
|
||||
sprintf(partbuf, "data%ld", req->partno);
|
||||
/* select the <data> tag for "normal" requests and the <connect> one
|
||||
for CONNECT requests (within the <reply> section) */
|
||||
const char *section= req->connect_request?"connect":"data";
|
||||
|
||||
if(req->partno)
|
||||
sprintf(partbuf, "%s%ld", section, req->partno);
|
||||
else
|
||||
sprintf(partbuf, "%s", section);
|
||||
|
||||
logmsg("Send response test%ld section <%s>", req->testno, partbuf);
|
||||
|
||||
stream=fopen(filename, "rb");
|
||||
if(!stream) {
|
||||
error = errno;
|
||||
logmsg("fopen() failed with error: %d %s", error, strerror(error));
|
||||
logmsg("Error opening file: %s", filename);
|
||||
logmsg("Couldn't open test file");
|
||||
logmsg(" [3] Error opening file: %s", filename);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
@@ -1111,8 +1087,7 @@ static int send_doc(curl_socket_t sock, struct httprequest *req)
|
||||
if(!stream) {
|
||||
error = errno;
|
||||
logmsg("fopen() failed with error: %d %s", error, strerror(error));
|
||||
logmsg("Error opening file: %s", filename);
|
||||
logmsg("Couldn't open test file");
|
||||
logmsg(" [4] Error opening file: %s", filename);
|
||||
if(ptr)
|
||||
free(ptr);
|
||||
return 0;
|
||||
@@ -1156,7 +1131,7 @@ static int send_doc(curl_socket_t sock, struct httprequest *req)
|
||||
if(!dump) {
|
||||
error = errno;
|
||||
logmsg("fopen() failed with error: %d %s", error, strerror(error));
|
||||
logmsg("Error opening file: %s", responsedump);
|
||||
logmsg(" [5] Error opening file: %s", responsedump);
|
||||
if(ptr)
|
||||
free(ptr);
|
||||
if(cmd)
|
||||
@@ -1389,8 +1364,8 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port)
|
||||
|
||||
static void http_connect(curl_socket_t *infdp,
|
||||
curl_socket_t rootfd,
|
||||
struct httprequest *req,
|
||||
const char *ipaddr)
|
||||
const char *ipaddr,
|
||||
unsigned short ipport)
|
||||
{
|
||||
curl_socket_t serverfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD};
|
||||
curl_socket_t clientfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD};
|
||||
@@ -1422,7 +1397,7 @@ static void http_connect(curl_socket_t *infdp,
|
||||
if(got_exit_signal)
|
||||
goto http_connect_cleanup;
|
||||
|
||||
serverfd[CTRL] = connect_to(ipaddr, req->connect_port);
|
||||
serverfd[CTRL] = connect_to(ipaddr, ipport);
|
||||
if(serverfd[CTRL] == CURL_SOCKET_BAD)
|
||||
goto http_connect_cleanup;
|
||||
|
||||
@@ -1539,7 +1514,7 @@ static void http_connect(curl_socket_t *infdp,
|
||||
/* skip this and close the socket if err < 0 */
|
||||
if(err >= 0) {
|
||||
err = send_doc(datafd, &req2);
|
||||
if(!err && (req2.testno == DOCNUMBER_CONNECT)) {
|
||||
if(!err && req2.connect_request) {
|
||||
/* sleep to prevent triggering libcurl known bug #39. */
|
||||
for(loop = 2; (loop > 0) && !got_exit_signal; loop--)
|
||||
wait_ms(250);
|
||||
@@ -1847,7 +1822,8 @@ static curl_socket_t accept_connection(curl_socket_t sock)
|
||||
/* returns 1 if the connection should be serviced again immediately, 0 if there
|
||||
is no data waiting, or < 0 if it should be closed */
|
||||
static int service_connection(curl_socket_t msgsock, struct httprequest *req,
|
||||
curl_socket_t listensock, const char *hostport)
|
||||
curl_socket_t listensock,
|
||||
const char *connecthost)
|
||||
{
|
||||
if(got_exit_signal)
|
||||
return -1;
|
||||
@@ -1878,17 +1854,7 @@ static int service_connection(curl_socket_t msgsock, struct httprequest *req,
|
||||
if(got_exit_signal)
|
||||
return -1;
|
||||
|
||||
if(DOCNUMBER_CONNECT == req->testno) {
|
||||
/* a CONNECT request, setup and talk the tunnel */
|
||||
if(!is_proxy) {
|
||||
logmsg("received CONNECT but isn't running as proxy! EXIT");
|
||||
}
|
||||
else
|
||||
http_connect(&msgsock, listensock, req, hostport);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((req->testno < 0) && (req->testno != DOCNUMBER_CONNECT)) {
|
||||
if(req->testno < 0) {
|
||||
logmsg("special request received, no persistency");
|
||||
return -1;
|
||||
}
|
||||
@@ -1897,6 +1863,18 @@ static int service_connection(curl_socket_t msgsock, struct httprequest *req,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(req->connect_request) {
|
||||
/* a CONNECT request, setup and talk the tunnel */
|
||||
if(!is_proxy) {
|
||||
logmsg("received CONNECT but isn't running as proxy!");
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
http_connect(&msgsock, listensock, connecthost, req->connect_port);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we got a CONNECT, loop and get another request as well! */
|
||||
|
||||
if(req->open) {
|
||||
@@ -1904,9 +1882,6 @@ static int service_connection(curl_socket_t msgsock, struct httprequest *req,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(req->testno == DOCNUMBER_CONNECT)
|
||||
return 1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1923,7 +1898,9 @@ int main(int argc, char *argv[])
|
||||
int error;
|
||||
int arg=1;
|
||||
long pid;
|
||||
const char *hostport = "127.0.0.1";
|
||||
const char *connecthost = "127.0.0.1";
|
||||
|
||||
/* a default CONNECT port is basically pointless but still ... */
|
||||
size_t socket_idx;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
@@ -1993,14 +1970,15 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
else if(!strcmp("--connect", argv[arg])) {
|
||||
/* store the connect host, but also use this as a hint that we
|
||||
run as a proxy and do a few different internal choices */
|
||||
/* The connect host IP number that the proxy will connect to no matter
|
||||
what the client asks for, but also use this as a hint that we run as
|
||||
a proxy and do a few different internal choices */
|
||||
arg++;
|
||||
if(argc>arg) {
|
||||
hostport = argv[arg];
|
||||
connecthost = argv[arg];
|
||||
arg++;
|
||||
is_proxy = TRUE;
|
||||
logmsg("Run as proxy, CONNECT to %s", hostport);
|
||||
logmsg("Run as proxy, CONNECT to host %s", connecthost);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -2184,7 +2162,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* Service this connection until it has nothing available */
|
||||
do {
|
||||
rc = service_connection(all_sockets[socket_idx], &req, sock, hostport);
|
||||
rc = service_connection(all_sockets[socket_idx], &req, sock,
|
||||
connecthost);
|
||||
if(got_exit_signal)
|
||||
goto sws_cleanup;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user