|
|
|
#include "response.h"
|
|
|
|
|
|
|
|
Response* newResponse(){
|
|
|
|
Response *response = malloc( sizeof( Response ) );
|
|
|
|
memset(response, 0, sizeof(Response));
|
|
|
|
response->headers = NULL;
|
|
|
|
response->statusMessage = NULL;
|
|
|
|
response->body = NULL;
|
|
|
|
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 = strdup("OK");
|
|
|
|
rsp->version = 1.1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void connectionEstablished(Response *rsp){
|
|
|
|
rsp->statusCode = 200;
|
|
|
|
rsp->statusMessage = strdup("Connection Established");
|
|
|
|
rsp->version = 1.1;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* responseToString( Response *rsp ){
|
|
|
|
// HTTP/x.x xxx OK \r\n
|
|
|
|
int fullLength = 13 + strlen(rsp->statusMessage) + 2 +
|
|
|
|
// Headers \r\n\r\n
|
|
|
|
headerListCharLength(rsp->headers) + 4;
|
|
|
|
|
|
|
|
if ( rsp->body != NULL ) fullLength += strlen(rsp->body) + 2;
|
|
|
|
|
|
|
|
char retString[fullLength];
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void responseSetBody(Response *rsp, char *string, bool updateContentLength){
|
|
|
|
rsp->body = strdup(string);
|
|
|
|
|
|
|
|
|
|
|
|
if ( updateContentLength ){
|
|
|
|
Header *contentLengthHeader = getHeader(rsp->headers, "content-length");
|
|
|
|
char *value = malloc(sizeof(char) * 20);
|
|
|
|
sprintf(value, "%lu", strlen(string) );
|
|
|
|
contentLengthHeader->value = strdup(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void responseAddHeader(Response *rsp, char header[]){
|
|
|
|
if ( rsp->headers == NULL ){
|
|
|
|
rsp->headers = malloc(sizeof( HeaderList ));
|
|
|
|
rsp->headers->header = newHeader( header );
|
|
|
|
rsp->headers->next = NULL;
|
|
|
|
} else
|
|
|
|
addHeader( rsp->headers, 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 *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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void freeResponse( Response *rsp ){
|
|
|
|
free(rsp->statusMessage);
|
|
|
|
freeHeaderList( rsp->headers );
|
|
|
|
free(rsp->body);
|
|
|
|
free(rsp);
|
|
|
|
}
|