Now working for simple, non-encrypted requests
making requests to something like example.com over a non-encrypted connection now works. Binary files are unlikely to work at the moment although I haven't tried. Also, non-encrypted doesn't work. I have also changed a little about how tests work. Requests tests now display much better.
This commit is contained in:
		
							parent
							
								
									a91a264a7a
								
							
						
					
					
						commit
						8a5bfe9b36
					
				
					 18 changed files with 725 additions and 148 deletions
				
			
		
							
								
								
									
										6
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
					@ -6,7 +6,7 @@ TESTFILES   = $(wildcard tests/*.c)
 | 
				
			||||||
TESTOUT = $(TESTFILES:.c=)
 | 
					TESTOUT = $(TESTFILES:.c=)
 | 
				
			||||||
OUT      = yaip
 | 
					OUT      = yaip
 | 
				
			||||||
CFLAGS   = -Wall -g
 | 
					CFLAGS   = -Wall -g
 | 
				
			||||||
LDLIBS   = -lsqlite3
 | 
					LDLIBS   = -lsqlite3 -lm
 | 
				
			||||||
CC = gcc
 | 
					CC = gcc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,8 +24,8 @@ $(OUT): $(OBJFILES)
 | 
				
			||||||
%.o: %.c
 | 
					%.o: %.c
 | 
				
			||||||
	$(CC) $(CFLAGS) -c -o $@ $^
 | 
						$(CC) $(CFLAGS) -c -o $@ $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tests/%.test: tests/%.test.c tests/munit/munit.c
 | 
					tests/%.test: tests/%.test.c tests/munit/munit.c $(filter-out src/main.o, $(OBJFILES))
 | 
				
			||||||
	$(CC) $? -o $@
 | 
						$(CC) -o $@ $^ $(LDLIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test-%: tests/%.test
 | 
					test-%: tests/%.test
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										71
									
								
								src/proxy.c
									
										
									
									
									
								
							
							
						
						
									
										71
									
								
								src/proxy.c
									
										
									
									
									
								
							| 
						 | 
					@ -1,12 +1,50 @@
 | 
				
			||||||
#include "proxy.h"
 | 
					#include "proxy.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void proxy_startListener(unsigned int port){
 | 
					Response *upstreamGetResponse(Request *request){
 | 
				
			||||||
 | 
						//Here we pretend to be a client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int client_fd = 0;
 | 
				
			||||||
 | 
						struct sockaddr_in address;
 | 
				
			||||||
 | 
						memset( &address, 0, sizeof(address) );
 | 
				
			||||||
 | 
						struct hostent *host = gethostbyname(request->host);
 | 
				
			||||||
 | 
						Response *rsp = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0){
 | 
				
			||||||
 | 
							perror("socket failed");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						address.sin_family = AF_INET;
 | 
				
			||||||
 | 
						address.sin_port = htons( 80 );
 | 
				
			||||||
 | 
						// We want the request to go out to whatever the host was resolved to
 | 
				
			||||||
 | 
						memcpy( &address.sin_addr, host->h_addr_list[0], host->h_length );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if((connect(client_fd, (struct sockaddr *)&address, sizeof(address)))<0)  {  
 | 
				
			||||||
 | 
							perror("connect failed");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char *toSend = requestToString(request);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( write( client_fd, toSend, strlen(toSend) ) != strlen(toSend) ){
 | 
				
			||||||
 | 
							perror( "Write Error" );
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rsp = newResponseFromSocket( client_fd );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rsp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void proxy_startListener(unsigned int port){
 | 
				
			||||||
 | 
						//we need to act as an http server
 | 
				
			||||||
	int server_fd, new_socket;
 | 
						int server_fd, new_socket;
 | 
				
			||||||
    struct sockaddr_in address;
 | 
					    struct sockaddr_in address;
 | 
				
			||||||
    int opt = 1;
 | 
						memset( &address, 0, sizeof(address) );
 | 
				
			||||||
    int addrlen = sizeof(address);
 | 
					    int addrlen = sizeof(address);
 | 
				
			||||||
	char *response;
 | 
						Response *response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Creating socket file descriptor
 | 
					    // Creating socket file descriptor
 | 
				
			||||||
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
 | 
					    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
 | 
				
			||||||
| 
						 | 
					@ -30,25 +68,44 @@ void proxy_startListener(unsigned int port){
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ( true ){
 | 
						while ( true ){
 | 
				
			||||||
		printf("Listening\n");
 | 
							printf("Listening on port %i\n", port);
 | 
				
			||||||
		if ((new_socket = accept(server_fd, (struct sockaddr *)&address, 
 | 
							if ((new_socket = accept(server_fd, (struct sockaddr *)&address, 
 | 
				
			||||||
				(socklen_t*)&addrlen))<0) {
 | 
									(socklen_t*)&addrlen))<0) {
 | 
				
			||||||
			perror("accept");
 | 
								perror("accept");
 | 
				
			||||||
			return ;
 | 
								return ;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//I think eventually I'd like a different thread here for each request
 | 
				
			||||||
 | 
							//Not sure how to do that yet though so I'll keep everything on the main
 | 
				
			||||||
 | 
							//thread
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Request *request = newRequestFromSocket(new_socket);
 | 
							Request *request = newRequestFromSocket(new_socket);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//If this is an https request - this is the first part
 | 
				
			||||||
 | 
							if ( strcmp( request->method, "CONNECT" ) == 0 ){
 | 
				
			||||||
 | 
								printf("\n\n%s\n\n", requestToString( request ));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If the host is not defined, then it is not a proxy request
 | 
				
			||||||
 | 
							// Note that the host here is where the request should be sent, not
 | 
				
			||||||
 | 
							// necesarily the hosts header
 | 
				
			||||||
		if ( strcmp( request->host, "" ) == 0 ){
 | 
							if ( strcmp( request->host, "" ) == 0 ){
 | 
				
			||||||
			response = webserverGetResponse(request);
 | 
								response = webserverGetResponse(request);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			printf("This is a proxy request\n");
 | 
								response = upstreamGetResponse(request);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		send(new_socket , response, strlen(response) , 0 );
 | 
							char *responseStr = responseToString( response );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// I'm also not convinced that strlen is the best function to use here
 | 
				
			||||||
 | 
							// When we get to dealing with binary requests / responses, they may
 | 
				
			||||||
 | 
							// well have null characters in them
 | 
				
			||||||
 | 
							send(new_socket , responseStr, strlen(responseStr) , 0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//close(new_socket);
 | 
							close(new_socket);
 | 
				
			||||||
 | 
							freeRequest( request );
 | 
				
			||||||
 | 
							freeResponse( response );
 | 
				
			||||||
 | 
							free(responseStr);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,8 @@
 | 
				
			||||||
#include <sys/socket.h>
 | 
					#include <sys/socket.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					#include <netdb.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,5 +15,6 @@
 | 
				
			||||||
#include "webserver.h"
 | 
					#include "webserver.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void proxy_startListener( unsigned int port );
 | 
					void proxy_startListener( unsigned int port );
 | 
				
			||||||
 | 
					Response *upstreamGetResponse(Request *request);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* ifndef PROXY_H */
 | 
					#endif /* ifndef PROXY_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										103
									
								
								src/request.c
									
										
									
									
									
								
							
							
						
						
									
										103
									
								
								src/request.c
									
										
									
									
									
								
							| 
						 | 
					@ -10,12 +10,13 @@ Request* newRequest(){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void requestFirstLine( Request *req, char line[] ){
 | 
					void requestFirstLine( Request *req, char line[] ){
 | 
				
			||||||
	char method[20] = {'\0'}; //Get, post, etc.
 | 
						char method[20] = {'\0'}; //Get, post, etc.
 | 
				
			||||||
	char *url = malloc(sizeof(char) *2048); // This may contain the method, the path, the domain and so on
 | 
						// This may contain the method, the path, the domain and so on
 | 
				
			||||||
 | 
						char *url = malloc(sizeof(char) *2048);
 | 
				
			||||||
	memset(url, '\0', sizeof(char) * 2048);
 | 
						memset(url, '\0', sizeof(char) * 2048);
 | 
				
			||||||
	char *currentPos;
 | 
						char *currentPos = url;
 | 
				
			||||||
	float version = 0;
 | 
						float version = 0;
 | 
				
			||||||
	char protocol[6] = {'\0'};
 | 
					 | 
				
			||||||
	char host[254] = {'\0'};
 | 
						char host[254] = {'\0'};
 | 
				
			||||||
 | 
						int port = -1; // 0 is a valid port number, -1 isn't
 | 
				
			||||||
	//https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
 | 
						//https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
 | 
				
			||||||
	char path[2000] = {'\0'};
 | 
						char path[2000] = {'\0'};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,33 +25,63 @@ void requestFirstLine( Request *req, char line[] ){
 | 
				
			||||||
	req->version = version;
 | 
						req->version = version;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	//We've pulled out the easy bits. Now to go through the url and pull out what we need
 | 
						//We've pulled out the easy bits. Now to go through the url and pull out what we need
 | 
				
			||||||
	currentPos = url;
 | 
						int protEnd = strpos(url, "://" );
 | 
				
			||||||
	sscanf( currentPos, "%5[^:/]", protocol );
 | 
						if ( protEnd > -1 ){
 | 
				
			||||||
	if ( strlen( protocol ) > 0 ){
 | 
							req->protocol = strndup( url, protEnd );
 | 
				
			||||||
		currentPos = currentPos + strlen(protocol) + 3;
 | 
							currentPos += protEnd + 3;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							req->protocol = "";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sscanf( currentPos, "%253[^:/]", host );
 | 
						sscanf( currentPos, "%253[^:/]", host );
 | 
				
			||||||
	if ( strlen( host ) > 0 ){
 | 
						if ( strlen( host ) > 0 ){
 | 
				
			||||||
		currentPos = currentPos + strlen(host);
 | 
							currentPos = currentPos + strlen(host);
 | 
				
			||||||
 | 
							req->host = strdup(host);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							req->host = "";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( currentPos[0] == ':' ){
 | 
				
			||||||
 | 
							currentPos++;
 | 
				
			||||||
 | 
							sscanf( currentPos, "%i", &port );
 | 
				
			||||||
 | 
							req->port = port;
 | 
				
			||||||
 | 
							currentPos += (int)floor( log10( port ) ) + 1;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							req->port = -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sscanf( currentPos, "%2000[^? ]", path );
 | 
						sscanf( currentPos, "%2000[^? ]", path );
 | 
				
			||||||
	if ( strlen( path ) > 0 ){
 | 
						if ( strlen( path ) > 0 ){
 | 
				
			||||||
		currentPos = currentPos + strlen(path);
 | 
							currentPos += strlen(path);
 | 
				
			||||||
 | 
							req->path = strdup(path);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							req->path = "";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req->protocol = malloc(sizeof(char) * strlen(protocol));
 | 
						if ( strlen( currentPos ) > 0 ){
 | 
				
			||||||
	strcpy(req->protocol, protocol);
 | 
							req->queryString = strdup( currentPos );
 | 
				
			||||||
	req->host = malloc(sizeof(char) * strlen(host));
 | 
						} else {
 | 
				
			||||||
	strcpy(req->host, host);
 | 
							req->queryString = "";
 | 
				
			||||||
	req->path = malloc(sizeof(char) * strlen(path));
 | 
						}
 | 
				
			||||||
	strcpy(req->path, path);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//The query string is anything left
 | 
						//We try and work out port and protocol if we don't have them
 | 
				
			||||||
	req->queryString = malloc(sizeof(char) * strlen(currentPos));
 | 
						if ( req->port == -1){
 | 
				
			||||||
	strcpy(req->queryString, currentPos);
 | 
							if ( strcmp( "https", req->protocol ) == 0 )
 | 
				
			||||||
 | 
								req->port = 443;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								req->port = 80;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( strlen(req->protocol) == 0 ){
 | 
				
			||||||
 | 
							if ( req->port == 443 )
 | 
				
			||||||
 | 
								req->protocol = "https";
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								req->protocol = "http";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(url);
 | 
						free(url);
 | 
				
			||||||
| 
						 | 
					@ -70,30 +101,38 @@ Request* newRequestFromSocket(int socket){
 | 
				
			||||||
	//from the body (if there is a body)
 | 
						//from the body (if there is a body)
 | 
				
			||||||
	valread = fdReadLine( socket, line, 1024);
 | 
						valread = fdReadLine( socket, line, 1024);
 | 
				
			||||||
	while ( valread > 2 ){
 | 
						while ( valread > 2 ){
 | 
				
			||||||
		printf("%s",line );
 | 
					 | 
				
			||||||
		requestAddHeader( req, line );
 | 
							requestAddHeader( req, line );
 | 
				
			||||||
 | 
					 | 
				
			||||||
		//I believe at this point all the headers are done.
 | 
							//I believe at this point all the headers are done.
 | 
				
			||||||
		valread = fdReadLine( socket , line, 1024);
 | 
							valread = fdReadLine( socket , line, 1024);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//TODO: make requests work with a body
 | 
				
			||||||
 | 
						//contentLength = getHeader( req->headers, "content-length" );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//if ( contentLength != NULL ){
 | 
				
			||||||
 | 
						//	printf( "Content length is %i\n", atoi(contentLength->value) );
 | 
				
			||||||
 | 
						//}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	return req;
 | 
						return req;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char* requestToString( Request *req, bool proxy){
 | 
					char* requestToString( Request *req){
 | 
				
			||||||
	unsigned int fullLength = strlen(req->method) + 1 + sizeof( req->path ) +
 | 
						unsigned int fullLength = strlen(req->method) + 1 + sizeof( req->path ) +
 | 
				
			||||||
 | 
							//11 = [space]http/1.1\r\n
 | 
				
			||||||
		sizeof( req->queryString ) + 11 + headerListCharLength( req->headers );
 | 
							sizeof( req->queryString ) + 11 + headerListCharLength( req->headers );
 | 
				
			||||||
	if ( proxy )
 | 
					
 | 
				
			||||||
		fullLength += sizeof(req->method) + 3 + sizeof(req->host);
 | 
						if ( strcmp( req->method, "CONNECT" ) == 0 )
 | 
				
			||||||
 | 
							fullLength += sizeof(req->host);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char retString[fullLength];
 | 
						char retString[fullLength];
 | 
				
			||||||
 | 
						memset( retString, '\0', fullLength );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (proxy)
 | 
						if ( strcmp( req->method, "CONNECT" ) == 0 )
 | 
				
			||||||
		sprintf(retString, "%s %s://%s%s%s HTTP/%.1f\r\n%s", req->method,
 | 
							sprintf(retString, "%s %s HTTP/%.1f\r\n%s\r\n", req->method,
 | 
				
			||||||
			req->method, req->host, req->path, req->queryString, req->version,
 | 
								req->host, req->version, headersToString(req->headers));
 | 
				
			||||||
			headersToString(req->headers));
 | 
					 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		sprintf(retString, "%s %s%s HTTP/%.1f\r\n%s", req->method,
 | 
							sprintf(retString, "%s %s%s HTTP/%.1f\r\n%s\r\n", req->method,
 | 
				
			||||||
			req->path, req->queryString, req->version,
 | 
								req->path, req->queryString, req->version,
 | 
				
			||||||
			headersToString(req->headers));
 | 
								headersToString(req->headers));
 | 
				
			||||||
	//	rsp->statusMessage,headersToString(rsp->headers),rsp->body);
 | 
						//	rsp->statusMessage,headersToString(rsp->headers),rsp->body);
 | 
				
			||||||
| 
						 | 
					@ -111,5 +150,15 @@ void requestAddHeader( Request *req, char header[] ){
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void freeRequest( Request *req ){
 | 
				
			||||||
 | 
						free(req->method);
 | 
				
			||||||
 | 
						free(req->protocol);
 | 
				
			||||||
 | 
						free(req->host);
 | 
				
			||||||
 | 
						free(req->path);
 | 
				
			||||||
 | 
						freeHeaderList( req->headers );
 | 
				
			||||||
 | 
						free(req->queryString);
 | 
				
			||||||
 | 
						free(req->body);
 | 
				
			||||||
 | 
						free(req);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,9 +6,12 @@
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
#include "readline.h"
 | 
					#include "readline.h"
 | 
				
			||||||
#include "requestresponse.h"
 | 
					#include "requestresponse.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "./util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -21,9 +24,10 @@ typedef struct {
 | 
				
			||||||
	char *protocol;
 | 
						char *protocol;
 | 
				
			||||||
	char *host;
 | 
						char *host;
 | 
				
			||||||
	char *path;
 | 
						char *path;
 | 
				
			||||||
 | 
						int port;
 | 
				
			||||||
	HeaderList *headers;
 | 
						HeaderList *headers;
 | 
				
			||||||
	char *queryString;
 | 
						char *queryString;
 | 
				
			||||||
	char *body;
 | 
						void *body;
 | 
				
			||||||
} Request;
 | 
					} Request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Request* newRequest();
 | 
					Request* newRequest();
 | 
				
			||||||
| 
						 | 
					@ -32,12 +36,11 @@ Request* newRequestFromSocket(int socket);
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
* requestToString
 | 
					* requestToString
 | 
				
			||||||
* @prarm req the request to convert
 | 
					* @prarm req the request to convert
 | 
				
			||||||
* @param proxy whether we want a proxy request (adds the host to the first line) 
 | 
					 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
char* requestToString( Request *req, bool proxy );
 | 
					char* requestToString( Request *req );
 | 
				
			||||||
void requestAddHeader( Request *req, char header[] );
 | 
					void requestAddHeader( Request *req, char header[] );
 | 
				
			||||||
//void* requestAddHeader(Request *req, char line[]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void freeRequest( Request *req );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* ifndef REQUEST_H */
 | 
					#endif /* ifndef REQUEST_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,42 +4,49 @@ Header* newHeader(char *str){
 | 
				
			||||||
	Header *header = malloc(sizeof(Header));
 | 
						Header *header = malloc(sizeof(Header));
 | 
				
			||||||
	memset(header, 0, sizeof(Header));
 | 
						memset(header, 0, sizeof(Header));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int position = -1;
 | 
					
 | 
				
			||||||
 | 
						char *position = str;
 | 
				
			||||||
 | 
						char *end = str + strlen(str) - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//Let's loose any trailing whitespace
 | 
				
			||||||
 | 
						while ( ( *end == '\n' || *end == '\r' ) && end > str ) end--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ( *position != ':' && position < end ) position++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for ( unsigned int i = 0; i < strlen(str); i++ ){
 | 
						if ( position == end ){
 | 
				
			||||||
		if ( str[i] == ':' ){
 | 
					 | 
				
			||||||
			position = i;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ( position == -1 ){
 | 
					 | 
				
			||||||
		printf("Header without colon. Not sure what to do\n");
 | 
							printf("Header without colon. Not sure what to do\n");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// We want to allocate 1 more than the length so we can have a \0 at the end
 | 
						header->name = malloc( sizeof(char) * ( position + 1 - str ) );
 | 
				
			||||||
	header->name = malloc( sizeof(char) * ( position + 1 ) );
 | 
						memset(header->name, '\0', position + 1 - str );
 | 
				
			||||||
	memset(header->name, '\0', position+1);
 | 
						strncpy( header->name, str, position - str );
 | 
				
			||||||
	strncpy( header->name, str, position );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for ( unsigned int i = position+1; i < strlen(str); i++ ){
 | 
						//Skip over the colon
 | 
				
			||||||
		if ( str[i] == '\t' || str[i] == ' ' ) continue;
 | 
						position++;
 | 
				
			||||||
		position = i;
 | 
						//Skip over any trailing whitespace
 | 
				
			||||||
		break;
 | 
						while ( *position == '\t' || *position == ' ' ) position++;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//Add 2 when allocating so that we have space for a \0 at the end
 | 
				
			||||||
	//Anything left is the value
 | 
						header->value = malloc( sizeof(char) * ( end + 2 - position ) );
 | 
				
			||||||
	header->value = malloc( sizeof(char) * ( strlen(str) - position ) );
 | 
						memset(header->value, '\0', ( end + 2 - position ) );
 | 
				
			||||||
	memset(header->value, '\0', ( strlen(str) - position ) );
 | 
						strncpy( header->value, position, end + 1 - position );
 | 
				
			||||||
	strcpy( header->value, str + position );
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	return header;
 | 
						return header;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void freeHeader(Header *header){
 | 
				
			||||||
 | 
						free(header->name);
 | 
				
			||||||
 | 
						free(header->value);
 | 
				
			||||||
 | 
						free(header);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void addHeader(HeaderList *headers, char *str){
 | 
					void addHeader(HeaderList *headers, char *str){
 | 
				
			||||||
	HeaderList *newListItem = malloc(sizeof(HeaderList));
 | 
						HeaderList *newListItem = malloc(sizeof(HeaderList));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,6 +60,16 @@ void addHeader(HeaderList *headers, char *str){
 | 
				
			||||||
	last->next = newListItem;
 | 
						last->next = newListItem;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void freeHeaderList(HeaderList *headers){
 | 
				
			||||||
 | 
						HeaderList *current;
 | 
				
			||||||
 | 
						while ( headers != NULL ){
 | 
				
			||||||
 | 
							current = headers;
 | 
				
			||||||
 | 
							freeHeader( current->header );
 | 
				
			||||||
 | 
							headers = headers->next;
 | 
				
			||||||
 | 
							free( current );
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Will return the first header in a header list with the name matching name
 | 
					// Will return the first header in a header list with the name matching name
 | 
				
			||||||
// It matches name case insensitively as header names are case insensitive
 | 
					// It matches name case insensitively as header names are case insensitive
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,9 +28,13 @@ struct HeaderList {
 | 
				
			||||||
//Creates a new header struct from a string like "Content-Length: 123"
 | 
					//Creates a new header struct from a string like "Content-Length: 123"
 | 
				
			||||||
Header* newHeader(char *str);
 | 
					Header* newHeader(char *str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void freeHeader(Header *header);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//Adds a header to the end of a header list
 | 
					//Adds a header to the end of a header list
 | 
				
			||||||
void addHeader(HeaderList *headers, char *str);
 | 
					void addHeader(HeaderList *headers, char *str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void freeHeaderList(HeaderList *headers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Header* getHeader(HeaderList *headers, char *name);
 | 
					Header* getHeader(HeaderList *headers, char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unsigned int countHeaders(HeaderList *headers);
 | 
					unsigned int countHeaders(HeaderList *headers);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,25 +3,38 @@
 | 
				
			||||||
Response* newResponse(){
 | 
					Response* newResponse(){
 | 
				
			||||||
	Response *response = malloc( sizeof( Response ) );
 | 
						Response *response = malloc( sizeof( Response ) );
 | 
				
			||||||
	memset(response, 0, sizeof(Response));
 | 
						memset(response, 0, sizeof(Response));
 | 
				
			||||||
	response->headers = malloc( sizeof( HeaderList ) );
 | 
						response->headers = NULL;
 | 
				
			||||||
	response->headers->header = newHeader("Content-Length: 0");
 | 
						response->statusMessage = NULL;
 | 
				
			||||||
	response->headers->next = NULL;
 | 
						response->body = NULL;
 | 
				
			||||||
	addHeader(response->headers, "Content-Type: text/plain");
 | 
					 | 
				
			||||||
	response->statusCode = 200;
 | 
					 | 
				
			||||||
	response->statusMessage = "OK";
 | 
					 | 
				
			||||||
	response->version = 1.1;
 | 
					 | 
				
			||||||
	return response;
 | 
						return response;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void responseBarebones(Response *rsp){
 | 
				
			||||||
 | 
						rsp->headers = malloc( sizeof( HeaderList ) );
 | 
				
			||||||
 | 
						rsp->headers->header = newHeader("Content-Length: 0");
 | 
				
			||||||
 | 
						rsp->headers->next = NULL;
 | 
				
			||||||
 | 
						addHeader(rsp->headers, "Content-Type: text/plain");
 | 
				
			||||||
 | 
						rsp->statusCode = 200;
 | 
				
			||||||
 | 
						rsp->statusMessage = "OK";
 | 
				
			||||||
 | 
						rsp->version = 1.1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char* responseToString( Response *rsp ){
 | 
					char* responseToString( Response *rsp ){
 | 
				
			||||||
	//               HTTP/x.x xxx      OK                       \r\n
 | 
						//               HTTP/x.x xxx      OK                       \r\n
 | 
				
			||||||
	int fullLength = 13 +           strlen(rsp->statusMessage) + 2 +
 | 
						int fullLength = 13 +           strlen(rsp->statusMessage) + 2 +
 | 
				
			||||||
	//      Headers                   \r\n\r\n
 | 
						//      Headers                   \r\n\r\n
 | 
				
			||||||
		headerListCharLength(rsp->headers) + 4 +        strlen(rsp->body);
 | 
							headerListCharLength(rsp->headers) + 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( rsp->body != NULL ) fullLength += strlen(rsp->body) + 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char retString[fullLength];
 | 
						char retString[fullLength];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sprintf(retString, "HTTP/%.1f %3d %s\r\n%s\r\n%s", rsp->version, rsp->statusCode,
 | 
					
 | 
				
			||||||
		rsp->statusMessage,headersToString(rsp->headers),rsp->body);
 | 
						sprintf(retString, "HTTP/%.1f %3d %s\r\n%s\r\n", rsp->version, rsp->statusCode,
 | 
				
			||||||
 | 
							rsp->statusMessage,headersToString(rsp->headers));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( rsp->body != NULL ) sprintf(retString + strlen(retString), "%s\r\n", (char *)rsp->body);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return strdup(retString);
 | 
						return strdup(retString);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,7 +60,65 @@ void responseAddHeader(Response *rsp, char header[]){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void responseFirstLine( Response *rsp, char line[] ){
 | 
				
			||||||
 | 
						// HTTP/1.1 200 OK
 | 
				
			||||||
 | 
						float version = 0;
 | 
				
			||||||
 | 
						int statusCode = 0;
 | 
				
			||||||
 | 
						char statusMessage[256] = {'\0'};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sscanf( line, "HTTP/%f %i %255[^\n]", &version, &statusCode, statusMessage );
 | 
				
			||||||
 | 
						rsp->version = version;
 | 
				
			||||||
 | 
						rsp->statusCode = statusCode;
 | 
				
			||||||
 | 
						rsp->statusMessage = strdup(statusMessage);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Response* newResponseFromSocket(int socket){
 | 
					Response* newResponseFromSocket(int socket){
 | 
				
			||||||
	Response *rsp = newResponse();
 | 
						Response *rsp = newResponse();
 | 
				
			||||||
 | 
						int valread;
 | 
				
			||||||
 | 
						char line[1024] = {0};
 | 
				
			||||||
 | 
						Header *contentLength = NULL;
 | 
				
			||||||
 | 
						unsigned int bodySize = 0, bodyRead = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						valread = fdReadLine( socket, line, 1024);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						responseFirstLine(rsp, line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//a length of 2 will indicate an empty line which will split the headers
 | 
				
			||||||
 | 
						//from the body (if there is a body)
 | 
				
			||||||
 | 
						valread = fdReadLine( socket, line, 1024);
 | 
				
			||||||
 | 
						while ( valread > 2 ){
 | 
				
			||||||
 | 
							responseAddHeader( rsp, line );
 | 
				
			||||||
 | 
							valread = fdReadLine( socket , line, 1024);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						//I believe at this point all the headers are done.
 | 
				
			||||||
 | 
						contentLength = getHeader( rsp->headers, "content-length" );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( contentLength != NULL ){
 | 
				
			||||||
 | 
							bodySize = atoi( contentLength->value );
 | 
				
			||||||
 | 
							if (bodySize > 0){
 | 
				
			||||||
 | 
								//When the body is not binary data, it is useful to treat it as a
 | 
				
			||||||
 | 
								//string. For this reason, I want the bite immediately after it to
 | 
				
			||||||
 | 
								//be \0
 | 
				
			||||||
 | 
								rsp->body = malloc( bodySize + 1 );
 | 
				
			||||||
 | 
								memset( rsp->body + bodySize + 1, '\0', 1 );
 | 
				
			||||||
 | 
								while ( bodyRead < bodySize ){
 | 
				
			||||||
 | 
									valread=read( socket, rsp->body + bodyRead, bodySize - bodyRead );
 | 
				
			||||||
 | 
									if (valread < 0){
 | 
				
			||||||
 | 
										perror("Unable to read");
 | 
				
			||||||
 | 
										return NULL;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									bodyRead += valread;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rsp;
 | 
						return rsp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void freeResponse( Response *rsp ){
 | 
				
			||||||
 | 
						free(rsp->statusMessage);
 | 
				
			||||||
 | 
						freeHeaderList( rsp->headers );
 | 
				
			||||||
 | 
						free(rsp->body);
 | 
				
			||||||
 | 
						free(rsp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,15 +20,30 @@ typedef struct {
 | 
				
			||||||
	int statusCode;
 | 
						int statusCode;
 | 
				
			||||||
	char *statusMessage;
 | 
						char *statusMessage;
 | 
				
			||||||
	HeaderList *headers;
 | 
						HeaderList *headers;
 | 
				
			||||||
	char *body;
 | 
						void *body;
 | 
				
			||||||
	unsigned int headerLength;
 | 
						unsigned int headerLength;
 | 
				
			||||||
} Response;
 | 
					} Response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Response* newResponse();
 | 
					Response* newResponse();
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* creates the minium viable valid response
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void responseBarebones(Response *rsp);
 | 
				
			||||||
char *responseToString(Response *rsp);
 | 
					char *responseToString(Response *rsp);
 | 
				
			||||||
 | 
					/* sets the body of a response to a string
 | 
				
			||||||
 | 
					* @param rsp the response
 | 
				
			||||||
 | 
					* @param string the string
 | 
				
			||||||
 | 
					* @param updateContentLength whether the content-length header should be auto-updated
 | 
				
			||||||
 | 
					* Note: if you want to set a binary body, use responseSetBodyRaw
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
void responseSetBody(Response *rsp, char *string, bool updateContentLength);
 | 
					void responseSetBody(Response *rsp, char *string, bool updateContentLength);
 | 
				
			||||||
 | 
					// TODO:
 | 
				
			||||||
 | 
					//void responseSetBodyRaw(Response *rsp, void *body, size_t size, bool updateContentLength);
 | 
				
			||||||
void responseAddHeader(Response *rsp, char header[]);
 | 
					void responseAddHeader(Response *rsp, char header[]);
 | 
				
			||||||
 | 
					Response* newResponseFromSocket(int socket);
 | 
				
			||||||
 | 
					void responseFirstLine( Response *req, char line[] );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void freeResponse( Response *rsp );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* ifndef REQUEST_H */
 | 
					#endif /* ifndef REQUEST_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										7
									
								
								src/util.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/util.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int strpos(char *haystack, char *needle) {
 | 
				
			||||||
 | 
						char *p = strstr(haystack, needle);
 | 
				
			||||||
 | 
						if ( p != NULL ) return p - haystack;
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/util.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/util.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					#ifndef UTIL_H
 | 
				
			||||||
 | 
					#define UTIL_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int strpos(char *haystack, char *needle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,8 @@
 | 
				
			||||||
#include "webserver.h"
 | 
					#include "webserver.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char* webserverGetResponse( Request *req ){
 | 
					Response* webserverGetResponse( Request *req ){
 | 
				
			||||||
	Response *rsp = newResponse();
 | 
						Response *rsp = newResponse();
 | 
				
			||||||
 | 
						responseBarebones(rsp);
 | 
				
			||||||
	responseSetBody(rsp, "Test", 1);
 | 
						responseSetBody(rsp, "Test", 1);
 | 
				
			||||||
	return responseToString(rsp);
 | 
						return rsp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,7 @@
 | 
				
			||||||
#include "request.h"
 | 
					#include "request.h"
 | 
				
			||||||
#include "response.h"
 | 
					#include "response.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char* webserverGetResponse( Request *req );
 | 
					Response* webserverGetResponse( Request *req );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* ifndef WEBSERVER_H
 | 
					#endif /* ifndef WEBSERVER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,12 +4,12 @@
 | 
				
			||||||
#include "munit/munit.h"
 | 
					#include "munit/munit.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "config.test.c"
 | 
					#include "config.test.c"
 | 
				
			||||||
#include "request.test.c"
 | 
					 | 
				
			||||||
#include "response.test.c"
 | 
					 | 
				
			||||||
#ifndef REQUESTRESPONSE_C
 | 
					#ifndef REQUESTRESPONSE_C
 | 
				
			||||||
#define REQUESTRESPONSE_C value
 | 
					#define REQUESTRESPONSE_C value
 | 
				
			||||||
#include "requestresponse.test.c"
 | 
					#include "requestresponse.test.c"
 | 
				
			||||||
#endif /* ifndef REQUESTRESPONSE_C */
 | 
					#endif /* ifndef REQUESTRESPONSE_C */
 | 
				
			||||||
 | 
					#include "request.test.c"
 | 
				
			||||||
 | 
					#include "response.test.c"
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,31 +1,41 @@
 | 
				
			||||||
#ifndef REQUEST_TEST
 | 
					#ifndef REQUEST_TEST
 | 
				
			||||||
#define REQUEST_TEST
 | 
					#define REQUEST_TEST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "munit/munit.h"
 | 
					#include "munit/munit.h"
 | 
				
			||||||
#include "../src/readline.c"
 | 
					
 | 
				
			||||||
#include "../src/request.c"
 | 
					#ifndef READLINE_C
 | 
				
			||||||
 | 
					#define READLINE_C
 | 
				
			||||||
 | 
					#include "../src/readline.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#include "../src/request.h"
 | 
				
			||||||
#ifndef REQUESTRESPONSE_C
 | 
					#ifndef REQUESTRESPONSE_C
 | 
				
			||||||
#define REQUESTRESPONSE_C
 | 
					#define REQUESTRESPONSE_C
 | 
				
			||||||
#include "../src/requestresponse.c"
 | 
					#include "../src/requestresponse.h"
 | 
				
			||||||
#endif /* ifndef REQUESTRESPONSE_C */
 | 
					#endif /* ifndef REQUESTRESPONSE_C */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
	char *fullLine;
 | 
						char *fullLine;
 | 
				
			||||||
	char *method;
 | 
						char *method;
 | 
				
			||||||
	char *host;
 | 
						char *host;
 | 
				
			||||||
 | 
						int port;
 | 
				
			||||||
	char *protocol;
 | 
						char *protocol;
 | 
				
			||||||
	double version;
 | 
						double version;
 | 
				
			||||||
	char *path;
 | 
						char *path;
 | 
				
			||||||
	char *queryString;
 | 
						char *queryString;
 | 
				
			||||||
} firstLine;
 | 
					} requestTestFirstLine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static firstLine line1Examples[] = {
 | 
					static requestTestFirstLine requestLine1Examples[] = {
 | 
				
			||||||
	//Full Line,                                             Method  Host           Protocol  Version  Path
 | 
						//Full Line,                                             Method     Host           Port  Protocol  Version  Path                 Query string
 | 
				
			||||||
	{ "GET /search?q=test HTTP/2",                           "GET",  "",            "",       2,       "/search",           "?q=test"},
 | 
						{ "GET /search?q=test HTTP/2",                           "GET",     "",            80,   "http",   2,       "/search",           "?q=test"},
 | 
				
			||||||
	{ "POST http://example.com/test HTTP/1.1",               "POST", "example.com", "http",   1.1,     "/test",             "" },
 | 
						{ "GET / HTTP/2",                                        "GET",     "",            80,   "http",   2,       "/",                 ""},
 | 
				
			||||||
	{ "POST https://example.com/test/test2/test3 HTTP/1.1",  "POST", "example.com", "https",  1.1,     "/test/test2/test3", ""},
 | 
						{ "POST http://example.com/test HTTP/1.1",               "POST",    "example.com", 80,   "http",   1.1,     "/test",             "" },
 | 
				
			||||||
	{ NULL,                                                   NULL,  NULL,           NULL,    0,       NULL,                NULL }
 | 
						{ "CONNECT example.com:443 HTTP/1.1",                    "CONNECT", "example.com", 443,  "https",  1.1,     "",                  "" },
 | 
				
			||||||
 | 
						{ "POST https://example.com/test/test2/test3 HTTP/1.1",  "POST",    "example.com", 443,  "https",  1.1,     "/test/test2/test3", ""},
 | 
				
			||||||
 | 
						{ "POST https://example.com:4444/test/ HTTP/1.1",        "POST",    "example.com", 4444, "https",  1.1,     "/test/",            ""},
 | 
				
			||||||
 | 
						{ NULL,                                                   NULL,     NULL,          80,    NULL,    0,       NULL,                NULL }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,72 +44,133 @@ static firstLine line1Examples[] = {
 | 
				
			||||||
MunitResult testFirstLineProtocols(const MunitParameter params[],
 | 
					MunitResult testFirstLineProtocols(const MunitParameter params[],
 | 
				
			||||||
		void* user_data_or_fixture){
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
	Request *req;
 | 
						Request *req;
 | 
				
			||||||
	for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){
 | 
						const char *firstLine = munit_parameters_get(params, "L1" );
 | 
				
			||||||
 | 
						requestTestFirstLine *line = requestLine1Examples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ( line->fullLine != NULL && strcmp( line->fullLine, firstLine ) != 0 )
 | 
				
			||||||
 | 
							line++;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if ( line->fullLine == NULL ) return MUNIT_ERROR;
 | 
				
			||||||
	req = newRequest();
 | 
						req = newRequest();
 | 
				
			||||||
	requestFirstLine( req, line->fullLine );
 | 
						requestFirstLine( req, line->fullLine );
 | 
				
			||||||
 | 
						munit_assert_not_null( req->protocol );
 | 
				
			||||||
	munit_assert_string_equal( req->protocol, line->protocol );
 | 
						munit_assert_string_equal( req->protocol, line->protocol );
 | 
				
			||||||
	free( req );
 | 
						free( req );
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return MUNIT_OK;
 | 
						return MUNIT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MunitResult testFirstLineMethod(const MunitParameter params[],
 | 
					MunitResult testFirstLineMethod(const MunitParameter params[],
 | 
				
			||||||
		void* user_data_or_fixture){
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
	Request *req;
 | 
						Request *req;
 | 
				
			||||||
	for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){
 | 
						const char *firstLine = munit_parameters_get(params, "L1" );
 | 
				
			||||||
 | 
						requestTestFirstLine *line = requestLine1Examples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ( line->fullLine != NULL && strcmp( line->fullLine, firstLine ) != 0 )
 | 
				
			||||||
 | 
							line++;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if ( line->fullLine == NULL ) return MUNIT_ERROR;
 | 
				
			||||||
	req = newRequest();
 | 
						req = newRequest();
 | 
				
			||||||
	requestFirstLine( req, line->fullLine );
 | 
						requestFirstLine( req, line->fullLine );
 | 
				
			||||||
 | 
						munit_assert_not_null( req->method );
 | 
				
			||||||
	munit_assert_string_equal( req->method, line->method );
 | 
						munit_assert_string_equal( req->method, line->method );
 | 
				
			||||||
	free( req );
 | 
						free( req );
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return MUNIT_OK;
 | 
						return MUNIT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MunitResult testFirstLineHosts(const MunitParameter params[],
 | 
					MunitResult testFirstLineHosts(const MunitParameter params[],
 | 
				
			||||||
		void* user_data_or_fixture){
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
	Request *req;
 | 
						Request *req;
 | 
				
			||||||
	for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){
 | 
						const char *firstLine = munit_parameters_get(params, "L1" );
 | 
				
			||||||
 | 
						requestTestFirstLine *line = requestLine1Examples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ( line->fullLine != NULL && strcmp( line->fullLine, firstLine ) != 0 )
 | 
				
			||||||
 | 
							line++;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if ( line->fullLine == NULL ) return MUNIT_ERROR;
 | 
				
			||||||
	req = newRequest();
 | 
						req = newRequest();
 | 
				
			||||||
	requestFirstLine( req, line->fullLine );
 | 
						requestFirstLine( req, line->fullLine );
 | 
				
			||||||
 | 
						munit_assert_not_null( req->host );
 | 
				
			||||||
	munit_assert_string_equal( req->host, line->host );
 | 
						munit_assert_string_equal( req->host, line->host );
 | 
				
			||||||
	free( req );
 | 
						free( req );
 | 
				
			||||||
 | 
						return MUNIT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MunitResult testFirstLinePorts(const MunitParameter params[],
 | 
				
			||||||
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
 | 
						Request *req;
 | 
				
			||||||
 | 
						const char *firstLine = munit_parameters_get(params, "L1" );
 | 
				
			||||||
 | 
						requestTestFirstLine *line = requestLine1Examples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ( line->fullLine != NULL && strcmp( line->fullLine, firstLine ) != 0 )
 | 
				
			||||||
 | 
							line++;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if ( line->fullLine == NULL ) return MUNIT_ERROR;
 | 
				
			||||||
 | 
						req = newRequest();
 | 
				
			||||||
 | 
						requestFirstLine( req, line->fullLine );
 | 
				
			||||||
 | 
						munit_assert_int( req->port, ==, line->port );
 | 
				
			||||||
 | 
						free( req );
 | 
				
			||||||
	return MUNIT_OK;
 | 
						return MUNIT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MunitResult testFirstLinePaths(const MunitParameter params[],
 | 
					MunitResult testFirstLinePaths(const MunitParameter params[],
 | 
				
			||||||
		void* user_data_or_fixture){
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
	Request *req;
 | 
						Request *req;
 | 
				
			||||||
	for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){
 | 
						const char *firstLine = munit_parameters_get(params, "L1" );
 | 
				
			||||||
 | 
						requestTestFirstLine *line = requestLine1Examples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ( line->fullLine != NULL && strcmp( line->fullLine, firstLine ) != 0 )
 | 
				
			||||||
 | 
							line++;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if ( line->fullLine == NULL ) return MUNIT_ERROR;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	req = newRequest();
 | 
						req = newRequest();
 | 
				
			||||||
	requestFirstLine( req, line->fullLine );
 | 
						requestFirstLine( req, line->fullLine );
 | 
				
			||||||
 | 
						munit_assert_not_null( req->path );
 | 
				
			||||||
	munit_assert_string_equal( req->path, line->path );
 | 
						munit_assert_string_equal( req->path, line->path );
 | 
				
			||||||
	free( req );
 | 
						free( req );
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return MUNIT_OK;
 | 
						return MUNIT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MunitResult testFirstLineVersions(const MunitParameter params[],
 | 
					MunitResult testFirstLineVersions(const MunitParameter params[],
 | 
				
			||||||
		void* user_data_or_fixture){
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Request *req;
 | 
						Request *req;
 | 
				
			||||||
	for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){
 | 
						const char *firstLine = munit_parameters_get(params, "L1" );
 | 
				
			||||||
 | 
						requestTestFirstLine *line = requestLine1Examples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ( line->fullLine != NULL && strcmp( line->fullLine, firstLine ) != 0 )
 | 
				
			||||||
 | 
							line++;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if ( line->fullLine == NULL ) return MUNIT_ERROR;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	req = newRequest();
 | 
						req = newRequest();
 | 
				
			||||||
	requestFirstLine( req, line->fullLine );
 | 
						requestFirstLine( req, line->fullLine );
 | 
				
			||||||
	munit_assert_float( req->version, ==, line->version );
 | 
						munit_assert_float( req->version, ==, line->version );
 | 
				
			||||||
	free( req );
 | 
						free( req );
 | 
				
			||||||
	}
 | 
					
 | 
				
			||||||
	return MUNIT_OK;
 | 
						return MUNIT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MunitResult testFirstLineQueryString(const MunitParameter params[],
 | 
					MunitResult testFirstLineQueryString(const MunitParameter params[],
 | 
				
			||||||
		void* user_data_or_fixture){
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
	Request *req;
 | 
						Request *req;
 | 
				
			||||||
	for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){
 | 
					
 | 
				
			||||||
 | 
						const char *firstLine = munit_parameters_get(params, "L1" );
 | 
				
			||||||
 | 
						requestTestFirstLine *line = requestLine1Examples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ( line->fullLine != NULL && strcmp( line->fullLine, firstLine ) != 0 )
 | 
				
			||||||
 | 
							line++;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if ( line->fullLine == NULL ) return MUNIT_ERROR;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	req = newRequest();
 | 
						req = newRequest();
 | 
				
			||||||
	requestFirstLine( req, line->fullLine );
 | 
						requestFirstLine( req, line->fullLine );
 | 
				
			||||||
 | 
						munit_assert_not_null( req->queryString );
 | 
				
			||||||
	munit_assert_string_equal( req->queryString, line->queryString );
 | 
						munit_assert_string_equal( req->queryString, line->queryString );
 | 
				
			||||||
	free( req );
 | 
						free( req );
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return MUNIT_OK;
 | 
						return MUNIT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -118,13 +189,15 @@ MunitResult testRequestToString(const MunitParameter params[],
 | 
				
			||||||
		void* user_data_or_fixture){
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
	Request *req = newRequest();
 | 
						Request *req = newRequest();
 | 
				
			||||||
	requestFirstLine( req, "GET /search?q=test HTTP/1.1" );
 | 
						requestFirstLine( req, "GET /search?q=test HTTP/1.1" );
 | 
				
			||||||
	munit_assert_string_equal( requestToString( req, 0 ), "GET /search?q=test HTTP/1.1\r\n" );
 | 
						munit_assert_string_equal( requestToString( req ), "GET /search?q=test HTTP/1.1\r\n\r\n" );
 | 
				
			||||||
	requestAddHeader( req, "Host: example.com" );
 | 
						requestAddHeader( req, "Host: example.com" );
 | 
				
			||||||
	munit_assert_string_equal( requestToString( req, 0 ), "GET /search?q=test HTTP/1.1\r\nHost: example.com\r\n" );
 | 
						munit_assert_string_equal( requestToString( req ), "GET /search?q=test HTTP/1.1\r\nHost: example.com\r\n\r\n" );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return MUNIT_OK;
 | 
						return MUNIT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MunitParameterEnum test_first_line_params[2] = {NULL, NULL};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static MunitTest request_tests[] = {
 | 
					static MunitTest request_tests[] = {
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		"/line1/versions", /* name */
 | 
							"/line1/versions", /* name */
 | 
				
			||||||
| 
						 | 
					@ -132,42 +205,49 @@ static MunitTest request_tests[] = {
 | 
				
			||||||
		NULL, /* setup */
 | 
							NULL, /* setup */
 | 
				
			||||||
		NULL, /* tear_down */
 | 
							NULL, /* tear_down */
 | 
				
			||||||
		MUNIT_TEST_OPTION_NONE, /* options */
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
		NULL /* parameters */
 | 
							test_first_line_params /* parameters */
 | 
				
			||||||
	}, {
 | 
						}, {
 | 
				
			||||||
		"/line1/methods", /* name */
 | 
							"/line1/methods", /* name */
 | 
				
			||||||
		testFirstLineMethod, /* test */
 | 
							testFirstLineMethod, /* test */
 | 
				
			||||||
		NULL, /* setup */
 | 
							NULL, /* setup */
 | 
				
			||||||
		NULL, /* tear_down */
 | 
							NULL, /* tear_down */
 | 
				
			||||||
		MUNIT_TEST_OPTION_NONE, /* options */
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
		NULL /* parameters */
 | 
							test_first_line_params /* parameters */
 | 
				
			||||||
	},{
 | 
						},{
 | 
				
			||||||
		"/line1/protocols", /* name */
 | 
							"/line1/protocols", /* name */
 | 
				
			||||||
		testFirstLineProtocols, /* test */
 | 
							testFirstLineProtocols, /* test */
 | 
				
			||||||
		NULL, /* setup */
 | 
							NULL, /* setup */
 | 
				
			||||||
		NULL, /* tear_down */
 | 
							NULL, /* tear_down */
 | 
				
			||||||
		MUNIT_TEST_OPTION_NONE, /* options */
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
		NULL /* parameters */
 | 
							test_first_line_params /* parameters */
 | 
				
			||||||
	},{
 | 
						},{
 | 
				
			||||||
		"/line1/hosts", /* name */
 | 
							"/line1/hosts", /* name */
 | 
				
			||||||
		testFirstLineHosts, /* test */
 | 
							testFirstLineHosts, /* test */
 | 
				
			||||||
		NULL, /* setup */
 | 
							NULL, /* setup */
 | 
				
			||||||
		NULL, /* tear_down */
 | 
							NULL, /* tear_down */
 | 
				
			||||||
		MUNIT_TEST_OPTION_NONE, /* options */
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
		NULL /* parameters */
 | 
							test_first_line_params /* parameters */
 | 
				
			||||||
 | 
						},{
 | 
				
			||||||
 | 
							"/line1/ports", /* name */
 | 
				
			||||||
 | 
							testFirstLinePorts, /* test */
 | 
				
			||||||
 | 
							NULL, /* setup */
 | 
				
			||||||
 | 
							NULL, /* tear_down */
 | 
				
			||||||
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
 | 
							test_first_line_params /* parameters */
 | 
				
			||||||
	},{
 | 
						},{
 | 
				
			||||||
		"/line1/paths", /* name */
 | 
							"/line1/paths", /* name */
 | 
				
			||||||
		testFirstLinePaths, /* test */
 | 
							testFirstLinePaths, /* test */
 | 
				
			||||||
		NULL, /* setup */
 | 
							NULL, /* setup */
 | 
				
			||||||
		NULL, /* tear_down */
 | 
							NULL, /* tear_down */
 | 
				
			||||||
		MUNIT_TEST_OPTION_NONE, /* options */
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
		NULL /* parameters */
 | 
							test_first_line_params /* parameters */
 | 
				
			||||||
	},{
 | 
						},{
 | 
				
			||||||
		"/line1/queryStrings", /* name */
 | 
							"/line1/queryStrings", /* name */
 | 
				
			||||||
		testFirstLineQueryString, /* test */
 | 
							testFirstLineQueryString, /* test */
 | 
				
			||||||
		NULL, /* setup */
 | 
							NULL, /* setup */
 | 
				
			||||||
		NULL, /* tear_down */
 | 
							NULL, /* tear_down */
 | 
				
			||||||
		MUNIT_TEST_OPTION_NONE, /* options */
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
		NULL /* parameters */
 | 
							test_first_line_params /* parameters */
 | 
				
			||||||
	},{
 | 
						},{
 | 
				
			||||||
		"/headers/add", /* name */
 | 
							"/headers/add", /* name */
 | 
				
			||||||
		testRequestAddHeader, /* test */
 | 
							testRequestAddHeader, /* test */
 | 
				
			||||||
| 
						 | 
					@ -200,6 +280,24 @@ MunitSuite request_test_suite = {
 | 
				
			||||||
#define MAINTEST
 | 
					#define MAINTEST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main (int argc, char* argv[]) {
 | 
					int main (int argc, char* argv[]) {
 | 
				
			||||||
 | 
						static char** firstLines;
 | 
				
			||||||
 | 
						unsigned int count = 1;
 | 
				
			||||||
 | 
						requestTestFirstLine *current = requestLine1Examples;
 | 
				
			||||||
 | 
						while ( current->fullLine != NULL ){
 | 
				
			||||||
 | 
							count++;
 | 
				
			||||||
 | 
							current++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						printf("There are %i request lines to test", count);
 | 
				
			||||||
 | 
						firstLines = malloc( sizeof( char * ) * ( count ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for( unsigned int i = 0; i < count; i++ ){
 | 
				
			||||||
 | 
							firstLines[i] = requestLine1Examples[i].fullLine;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_first_line_params[0].name = "L1";
 | 
				
			||||||
 | 
						test_first_line_params[0].values = firstLines;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return munit_suite_main(&request_test_suite, NULL, argc, argv);
 | 
						return munit_suite_main(&request_test_suite, NULL, argc, argv);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,19 +10,26 @@ typedef struct {
 | 
				
			||||||
	char *value;
 | 
						char *value;
 | 
				
			||||||
} HeaderTestCase;
 | 
					} HeaderTestCase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//Not that some of these have trailing \r and \n in the full lines
 | 
				
			||||||
 | 
					//These should be removed when turning it into a header struct
 | 
				
			||||||
static HeaderTestCase testCases[] = {
 | 
					static HeaderTestCase testCases[] = {
 | 
				
			||||||
	{ "Content-Encoding: gzip", "Content-Encoding", "gzip" },
 | 
						{ "Content-Encoding: gzip", "Content-Encoding", "gzip" },
 | 
				
			||||||
	{ "Accept-Ranges: bytes", "Accept-Ranges", "bytes" },
 | 
						{ "Accept-Ranges: bytes", "Accept-Ranges", "bytes" },
 | 
				
			||||||
	{ "Age: 186432", "Age", "186432" },
 | 
						{ "Age: 186432\n", "Age", "186432" },
 | 
				
			||||||
	{ "Cache-Control: max-age=604800", "Cache-Control", "max-age=604800" },
 | 
						{ "Cache-Control: max-age=604800", "Cache-Control", "max-age=604800" },
 | 
				
			||||||
	{ "Content-Type: text/html; charset=UTF-8", "Content-Type", "text/html; charset=UTF-8" },
 | 
						{ "Content-Type: text/html; charset=UTF-8", "Content-Type", "text/html; charset=UTF-8" },
 | 
				
			||||||
	{ "Date: Thu, 06 Jan 2022 18:52:13 GMT", "Date", "Thu, 06 Jan 2022 18:52:13 GMT" },
 | 
						{ "Date: Thu, 06 Jan 2022 18:52:13 GMT\r", "Date", "Thu, 06 Jan 2022 18:52:13 GMT" },
 | 
				
			||||||
	{ "Etag: \"3147526947+ident\"", "Etag", "\"3147526947+ident\"" },
 | 
						{ "Etag: \"3147526947+ident\"", "Etag", "\"3147526947+ident\"" },
 | 
				
			||||||
	{ "Expires: Thu, 13 Jan 2022 18:52:13 GMT", "Expires", "Thu, 13 Jan 2022 18:52:13 GMT" },
 | 
						{ "Expires: Thu, 13 Jan 2022 18:52:13 GMT", "Expires", "Thu, 13 Jan 2022 18:52:13 GMT" },
 | 
				
			||||||
	{ "Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT", "Last-Modified", "Thu, 17 Oct 2019 07:18:26 GMT" },
 | 
						{ "Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT\r\n\r\n", "Last-Modified", "Thu, 17 Oct 2019 07:18:26 GMT" },
 | 
				
			||||||
	{ "Server: ECS (nyb/1D13)", "Server", "ECS (nyb/1D13)" },
 | 
						{ "Server: ECS (nyb/1D13)", "Server", "ECS (nyb/1D13)" },
 | 
				
			||||||
	{ "X-Cache: HIT", "X-Cache", "HIT" },
 | 
						{ "X-Cache: HIT", "X-Cache", "HIT" },
 | 
				
			||||||
	{ "Content-Length: 648", "Content-Length", "648" }
 | 
						{ "Content-Length: 648", "Content-Length", "648" },
 | 
				
			||||||
 | 
						//These are request heaedrs but should work the same way
 | 
				
			||||||
 | 
						{ "Host: example.com\r\n", "Host", "example.com" },
 | 
				
			||||||
 | 
						{ "User-Agent: curl/7.80.0", "User-Agent", "curl/7.80.0" },
 | 
				
			||||||
 | 
						{ "Accept: */*", "Accept", "*/*" },
 | 
				
			||||||
 | 
						{ "Accept: */*", "Accept", "*/*" },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MunitResult testHeadersName(const MunitParameter params[],
 | 
					MunitResult testHeadersName(const MunitParameter params[],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,46 @@
 | 
				
			||||||
#ifndef RESPONSE_TEST
 | 
					#ifndef RESPONSE_TEST
 | 
				
			||||||
#define RESPONSE_TEST value
 | 
					#define RESPONSE_TEST value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					#include <netdb.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "munit/munit.h"
 | 
					#include "munit/munit.h"
 | 
				
			||||||
 | 
					#ifndef READLINE_C
 | 
				
			||||||
 | 
					#define READLINE_C
 | 
				
			||||||
 | 
					#include "../src/readline.c"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#ifndef REQUESTRESPONSE_C
 | 
					#ifndef REQUESTRESPONSE_C
 | 
				
			||||||
#define REQUESTRESPONSE_C value
 | 
					#define REQUESTRESPONSE_C
 | 
				
			||||||
#include "../src/requestresponse.c"
 | 
					#include "../src/requestresponse.c"
 | 
				
			||||||
#endif /* ifndef REQUESTRESPONSE_C */
 | 
					#endif /* ifndef REQUESTRESPONSE_C */
 | 
				
			||||||
#include "../src/response.c"
 | 
					#include "../src/response.c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
						char *fullLine;
 | 
				
			||||||
 | 
						float version;
 | 
				
			||||||
 | 
						int statusCode;
 | 
				
			||||||
 | 
						char *statusMessage;
 | 
				
			||||||
 | 
					} firstLine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static firstLine line1Examples[] = {
 | 
				
			||||||
 | 
						//Full Line,               version      status Code       Status Message
 | 
				
			||||||
 | 
						{ "HTTP/1.1 200 OK",         1.1,        200,               "OK" },
 | 
				
			||||||
 | 
						{ "HTTP/2.0 404 Not Found",  2.0,        404,               "Not Found" },
 | 
				
			||||||
 | 
						{ NULL,                      0,          0,                 NULL }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MunitResult testResponseNewStatus(const MunitParameter params[],
 | 
					MunitResult testResponseNewStatus(const MunitParameter params[],
 | 
				
			||||||
		void* user_data_or_fixture){
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
	Response *rsp = newResponse();
 | 
						Response *rsp = newResponse();
 | 
				
			||||||
 | 
						responseBarebones(rsp);
 | 
				
			||||||
	munit_assert_int( rsp->statusCode, ==, 200 );
 | 
						munit_assert_int( rsp->statusCode, ==, 200 );
 | 
				
			||||||
	return MUNIT_OK;
 | 
						return MUNIT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -19,6 +48,7 @@ MunitResult testResponseNewStatus(const MunitParameter params[],
 | 
				
			||||||
MunitResult testResponseNewStatusMessage(const MunitParameter params[],
 | 
					MunitResult testResponseNewStatusMessage(const MunitParameter params[],
 | 
				
			||||||
		void* user_data_or_fixture){
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
	Response *rsp = newResponse();
 | 
						Response *rsp = newResponse();
 | 
				
			||||||
 | 
						responseBarebones(rsp);
 | 
				
			||||||
	munit_assert_string_equal( rsp->statusMessage, "OK" );
 | 
						munit_assert_string_equal( rsp->statusMessage, "OK" );
 | 
				
			||||||
	return MUNIT_OK;
 | 
						return MUNIT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -26,6 +56,7 @@ MunitResult testResponseNewStatusMessage(const MunitParameter params[],
 | 
				
			||||||
MunitResult testResponseNewVersion(const MunitParameter params[],
 | 
					MunitResult testResponseNewVersion(const MunitParameter params[],
 | 
				
			||||||
		void* user_data_or_fixture){
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
	Response *rsp = newResponse();
 | 
						Response *rsp = newResponse();
 | 
				
			||||||
 | 
						responseBarebones(rsp);
 | 
				
			||||||
	munit_assert_float( rsp->version, ==, 1.1 );
 | 
						munit_assert_float( rsp->version, ==, 1.1 );
 | 
				
			||||||
	return MUNIT_OK;
 | 
						return MUNIT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -33,6 +64,7 @@ MunitResult testResponseNewVersion(const MunitParameter params[],
 | 
				
			||||||
MunitResult testResponseSetBody(const MunitParameter params[],
 | 
					MunitResult testResponseSetBody(const MunitParameter params[],
 | 
				
			||||||
		void* user_data_or_fixture){
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
	Response *rsp = newResponse();
 | 
						Response *rsp = newResponse();
 | 
				
			||||||
 | 
						responseBarebones(rsp);
 | 
				
			||||||
	responseSetBody( rsp, "Testing", 1 );
 | 
						responseSetBody( rsp, "Testing", 1 );
 | 
				
			||||||
	munit_assert_string_equal( rsp->body, "Testing" );
 | 
						munit_assert_string_equal( rsp->body, "Testing" );
 | 
				
			||||||
	munit_assert_string_equal( getHeader( rsp->headers, "content-length" )->value, "7" );
 | 
						munit_assert_string_equal( getHeader( rsp->headers, "content-length" )->value, "7" );
 | 
				
			||||||
| 
						 | 
					@ -42,11 +74,122 @@ MunitResult testResponseSetBody(const MunitParameter params[],
 | 
				
			||||||
MunitResult testResponseToString(const MunitParameter params[],
 | 
					MunitResult testResponseToString(const MunitParameter params[],
 | 
				
			||||||
		void* user_data_or_fixture){
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
	Response *rsp = newResponse();
 | 
						Response *rsp = newResponse();
 | 
				
			||||||
 | 
						responseBarebones(rsp);
 | 
				
			||||||
 | 
						munit_assert_string_equal( responseToString( rsp ), "HTTP/1.1 200 OK\r\nContent-Length: 0\r\nContent-Type: text/plain\r\n\r\n" );
 | 
				
			||||||
	responseSetBody( rsp, "Testing", 1 );
 | 
						responseSetBody( rsp, "Testing", 1 );
 | 
				
			||||||
	munit_assert_string_equal( responseToString( rsp ), "HTTP/1.1 200 OK\r\nContent-Length: 7\r\nContent-Type: text/plain\r\n\r\nTesting" );
 | 
						munit_assert_string_equal( responseToString( rsp ), "HTTP/1.1 200 OK\r\nContent-Length: 7\r\nContent-Type: text/plain\r\n\r\nTesting\r\n" );
 | 
				
			||||||
	return MUNIT_OK;
 | 
						return MUNIT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MunitResult testResponseFirstLineStatusCode(const MunitParameter params[],
 | 
				
			||||||
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
 | 
						Response *rsp;
 | 
				
			||||||
 | 
						for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){
 | 
				
			||||||
 | 
							rsp = newResponse();
 | 
				
			||||||
 | 
							responseFirstLine( rsp, line->fullLine );
 | 
				
			||||||
 | 
							munit_assert_int( rsp->statusCode, ==, line->statusCode );
 | 
				
			||||||
 | 
							free( rsp );
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return MUNIT_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MunitResult testResponseFirstLineStatusMessage(const MunitParameter params[],
 | 
				
			||||||
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
 | 
						Response *rsp;
 | 
				
			||||||
 | 
						for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){
 | 
				
			||||||
 | 
							rsp = newResponse();
 | 
				
			||||||
 | 
							responseFirstLine( rsp, line->fullLine );
 | 
				
			||||||
 | 
							munit_assert_string_equal( rsp->statusMessage, line->statusMessage );
 | 
				
			||||||
 | 
							free( rsp );
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return MUNIT_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MunitResult testResponseFirstLineVersion(const MunitParameter params[],
 | 
				
			||||||
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
 | 
						Response *rsp;
 | 
				
			||||||
 | 
						for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){
 | 
				
			||||||
 | 
							rsp = newResponse();
 | 
				
			||||||
 | 
							responseFirstLine( rsp, line->fullLine );
 | 
				
			||||||
 | 
							munit_assert_float( rsp->version, ==, line->version );
 | 
				
			||||||
 | 
							free( rsp );
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return MUNIT_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void* setupSocketTests(const MunitParameter params[], void* user_data) {
 | 
				
			||||||
 | 
						int client_fd = 0;
 | 
				
			||||||
 | 
						struct sockaddr_in address;
 | 
				
			||||||
 | 
						memset( &address, 0, sizeof(address) );
 | 
				
			||||||
 | 
						struct hostent *host = gethostbyname("example.com");
 | 
				
			||||||
 | 
						Response *rsp = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0){
 | 
				
			||||||
 | 
							perror("socket failed");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						address.sin_family = AF_INET;
 | 
				
			||||||
 | 
						address.sin_port = htons( 80 );
 | 
				
			||||||
 | 
						// We want the request to go out to whatever the host was resolved to
 | 
				
			||||||
 | 
						memcpy( &address.sin_addr, host->h_addr_list[0], host->h_length );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if((connect(client_fd, (struct sockaddr *)&address, sizeof(address)))<0)  {  
 | 
				
			||||||
 | 
							perror("connect failed");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char *toSend = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( write( client_fd, toSend, strlen(toSend) ) != strlen(toSend) ){
 | 
				
			||||||
 | 
							perror( "Write Error" );
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rsp = newResponseFromSocket( client_fd );
 | 
				
			||||||
 | 
						return rsp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MunitResult testResponseFromSocketHeaderLength(const MunitParameter params[],
 | 
				
			||||||
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
 | 
						Response *rsp = ( Response * )user_data_or_fixture;
 | 
				
			||||||
 | 
						if ( rsp == NULL ) return MUNIT_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//Check there are the right nubmer of haeders
 | 
				
			||||||
 | 
						// Unfortunately it changes from request to request so this is a "loose"
 | 
				
			||||||
 | 
						// check
 | 
				
			||||||
 | 
						munit_assert_int( countHeaders( rsp->headers ), >, 7 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return MUNIT_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MunitResult testResponseFromSocketStatusCode(const MunitParameter params[],
 | 
				
			||||||
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
 | 
						Response *rsp = ( Response * )user_data_or_fixture;
 | 
				
			||||||
 | 
						if ( rsp == NULL ) return MUNIT_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//Check there are the right nubmer of haeders
 | 
				
			||||||
 | 
						munit_assert_int( rsp->statusCode, ==, 200 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return MUNIT_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MunitResult testResponseFromSocketBody(const MunitParameter params[],
 | 
				
			||||||
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
 | 
						Response *rsp = ( Response * )user_data_or_fixture;
 | 
				
			||||||
 | 
						Header *contentLength = getHeader( rsp->headers, "content-length" );
 | 
				
			||||||
 | 
						unsigned int length = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( contentLength == NULL ) return MUNIT_ERROR;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						munit_assert_int( atoi( contentLength->value ), ==, strlen( (char *)rsp->body ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//Check there are the right nubmer of haeders
 | 
				
			||||||
 | 
						munit_assert_int( rsp->statusCode, ==, 200 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return MUNIT_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static MunitTest response_tests[] = {
 | 
					static MunitTest response_tests[] = {
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -84,6 +227,48 @@ static MunitTest response_tests[] = {
 | 
				
			||||||
		NULL, /* tear_down */
 | 
							NULL, /* tear_down */
 | 
				
			||||||
		MUNIT_TEST_OPTION_NONE, /* options */
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
		NULL /* parameters */
 | 
							NULL /* parameters */
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"/line1/statusCode", /* name */
 | 
				
			||||||
 | 
							testResponseFirstLineStatusCode, /* test */
 | 
				
			||||||
 | 
							NULL, /* setup */
 | 
				
			||||||
 | 
							NULL, /* tear_down */
 | 
				
			||||||
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
 | 
							NULL /* parameters */
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"/line1/statusMessage", /* name */
 | 
				
			||||||
 | 
							testResponseFirstLineStatusMessage, /* test */
 | 
				
			||||||
 | 
							NULL, /* setup */
 | 
				
			||||||
 | 
							NULL, /* tear_down */
 | 
				
			||||||
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
 | 
							NULL /* parameters */
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"/line1/version", /* name */
 | 
				
			||||||
 | 
							testResponseFirstLineVersion, /* test */
 | 
				
			||||||
 | 
							NULL, /* setup */
 | 
				
			||||||
 | 
							NULL, /* tear_down */
 | 
				
			||||||
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
 | 
							NULL /* parameters */
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"/fromSocket/headerLength", /* name */
 | 
				
			||||||
 | 
							testResponseFromSocketHeaderLength, /* test */
 | 
				
			||||||
 | 
							setupSocketTests, /* setup */
 | 
				
			||||||
 | 
							NULL, /* tear_down */
 | 
				
			||||||
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
 | 
							NULL /* parameters */
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"/fromSocket/statusCode", /* name */
 | 
				
			||||||
 | 
							testResponseFromSocketStatusCode, /* test */
 | 
				
			||||||
 | 
							setupSocketTests, /* setup */
 | 
				
			||||||
 | 
							NULL, /* tear_down */
 | 
				
			||||||
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
 | 
							NULL /* parameters */
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"/fromSocket/body", /* name */
 | 
				
			||||||
 | 
							testResponseFromSocketBody, /* test */
 | 
				
			||||||
 | 
							setupSocketTests, /* setup */
 | 
				
			||||||
 | 
							NULL, /* tear_down */
 | 
				
			||||||
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
 | 
							NULL /* parameters */
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
/* Mark the end of the array with an entry where the test
 | 
					/* Mark the end of the array with an entry where the test
 | 
				
			||||||
* function is NULL */
 | 
					* function is NULL */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										51
									
								
								tests/util.test.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								tests/util.test.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,51 @@
 | 
				
			||||||
 | 
					#ifndef UTIL_TEST
 | 
				
			||||||
 | 
					#define UTIL_TEST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "munit/munit.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../src/util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MunitResult testStrPos(const MunitParameter params[],
 | 
				
			||||||
 | 
							void* user_data_or_fixture){
 | 
				
			||||||
 | 
						munit_assert_int( strpos( "thisisatest", "test" ), ==, 7 );
 | 
				
			||||||
 | 
						munit_assert_int( strpos( "testthisisatest", "test" ), ==, 0 );
 | 
				
			||||||
 | 
						munit_assert_int( strpos( "blar", "test" ), ==, -1 );
 | 
				
			||||||
 | 
						return MUNIT_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static MunitTest util_tests[] = {
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							"/util/versions", /* name */
 | 
				
			||||||
 | 
							testStrPos, /* test */
 | 
				
			||||||
 | 
							NULL, /* setup */
 | 
				
			||||||
 | 
							NULL, /* tear_down */
 | 
				
			||||||
 | 
							MUNIT_TEST_OPTION_NONE, /* options */
 | 
				
			||||||
 | 
							NULL /* parameters */
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					/* Mark the end of the array with an entry where the test
 | 
				
			||||||
 | 
					* function is NULL */
 | 
				
			||||||
 | 
						{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MunitSuite util_test_suite = {
 | 
				
			||||||
 | 
						"/request", /* name */
 | 
				
			||||||
 | 
						util_tests, /* tests */
 | 
				
			||||||
 | 
						NULL, /* suites */
 | 
				
			||||||
 | 
						1, /* iterations */
 | 
				
			||||||
 | 
						MUNIT_SUITE_OPTION_NONE /* options */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef MAINTEST
 | 
				
			||||||
 | 
					#define MAINTEST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main (int argc, char* argv[]) {
 | 
				
			||||||
 | 
						return munit_suite_main(&util_test_suite, NULL, argc, argv);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* ifndef MAINTEST */
 | 
				
			||||||
 | 
					#endif /* ifndef REQUEST_TEST */
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue