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:
Daniel Stenberg
2013-03-15 17:28:32 +01:00
parent 142755fa5c
commit 1e29d275c6
30 changed files with 495 additions and 263 deletions

View File

@@ -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;