I have made a start
I have done some work on opening a socket and waiting for a connection. This can be read line by line and I have started a request struct that it will accept. Also started on some docs. Not much is yet working. I am going to start learning µnit for unit tests: https://nemequ.github.io/munit/
This commit is contained in:
parent
4e17e706fa
commit
f48a110429
15 changed files with 599 additions and 1 deletions
28
Makefile
Normal file
28
Makefile
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# This was stolen from here: https://avikdas.com/2019/12/16/makefiles-for-c-cpp-projects.html
|
||||||
|
|
||||||
|
CFILES = $(wildcard src/*.c)
|
||||||
|
OBJFILES = $(CFILES:.c=.o)
|
||||||
|
OUT = proxy
|
||||||
|
CFLAGS = -Wall
|
||||||
|
LDLIBS = -lsqlite3
|
||||||
|
CC = gcc
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: default
|
||||||
|
default: $(OUT)
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run: $(OUT)
|
||||||
|
./$(OUT)
|
||||||
|
|
||||||
|
$(OUT): $(OBJFILES)
|
||||||
|
$(CC) -o $@ $^ $(LDLIBS)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $^
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJFILES) $(OUT)
|
|
@ -1,6 +1,7 @@
|
||||||
# Intercepting Proxy in C
|
# YAIP
|
||||||
|
|
||||||
This will hopefully one day be an intercepting proxy written in c. I am using it
|
This will hopefully one day be an intercepting proxy written in c. I am using it
|
||||||
as a way to learn rather than as a tool I expect other people to use. However,
|
as a way to learn rather than as a tool I expect other people to use. However,
|
||||||
if you wish to, you are welcome to use this.
|
if you wish to, you are welcome to use this.
|
||||||
|
|
||||||
|
Check laws in your local area, this tool should only be used for legal purposes.
|
||||||
|
|
79
docs/config.md
Normal file
79
docs/config.md
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
# Config
|
||||||
|
|
||||||
|
There will be 2 config files available. One at
|
||||||
|
|
||||||
|
$XDG_CONFIG_HOME/yaip/proxy.conf and one at proxy.conf in the directory that the
|
||||||
|
tool is run from. Either can be overwritten with command line flags.
|
||||||
|
|
||||||
|
The config file is (currently), very simple. Empty lines are ignored, as are
|
||||||
|
lines that start with a # symbol. This is useful if you wish to make comments
|
||||||
|
about configuration choices.
|
||||||
|
|
||||||
|
The file in $XDG_CONFIG_HOME is parsed first, followed by the file in the
|
||||||
|
current working directory meaning that the config file in the current directory
|
||||||
|
will take precedence.
|
||||||
|
|
||||||
|
To set a configuration option, the line should have the configuration option
|
||||||
|
followed by a colon, an optional space and the value it should be set to.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
port: 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
All options may also be set via a command line switch -c or --config followed by the name
|
||||||
|
and the value.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
yaip --config port 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Available Options
|
||||||
|
|
||||||
|
### port
|
||||||
|
|
||||||
|
The listening port.
|
||||||
|
|
||||||
|
Default:
|
||||||
|
|
||||||
|
```
|
||||||
|
port: 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
### database
|
||||||
|
|
||||||
|
The database that requests and responses should be stored in.
|
||||||
|
|
||||||
|
Default:
|
||||||
|
|
||||||
|
```
|
||||||
|
database: proxy.sqlite
|
||||||
|
```
|
||||||
|
|
||||||
|
### localConfig
|
||||||
|
|
||||||
|
The name of the local config file:
|
||||||
|
|
||||||
|
Default:
|
||||||
|
|
||||||
|
```
|
||||||
|
localConfig: proxy.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
### userConfig
|
||||||
|
|
||||||
|
The name of the user config file:
|
||||||
|
|
||||||
|
Default:
|
||||||
|
|
||||||
|
```
|
||||||
|
$XDG_CONFIG_HOME/yaip/proxy.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** It only makes sense to change this as a command line argument as it is
|
||||||
|
the first config file that is sourced.
|
||||||
|
|
28
docs/plugins.md
Normal file
28
docs/plugins.md
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Plugins
|
||||||
|
|
||||||
|
**Note:** This is not implemented yet - it is mearly my plan.
|
||||||
|
|
||||||
|
The tool should be able to load plugins. These should be stand alone scripts /
|
||||||
|
executables that YAIP can call using `system()` or similar.
|
||||||
|
|
||||||
|
I will use a hook / filter type system. There will be different things that
|
||||||
|
plugins can do. The order in which plugins run will be dictated in the config
|
||||||
|
file or via an API if already running. The API still needs to be thought out.
|
||||||
|
|
||||||
|
## Intercept Plugins
|
||||||
|
|
||||||
|
Plugins will be able to intercept requests / responses. This will be blocking.
|
||||||
|
I haven't decided yet if these plugins will run on stdin or a temporary file.
|
||||||
|
|
||||||
|
I would prefer stdin / stdout although I think that would make it difficult for
|
||||||
|
a plugin to launch vim and have it be interactive. I'll have to do some trial
|
||||||
|
and error.
|
||||||
|
|
||||||
|
## Analysis Plugins
|
||||||
|
|
||||||
|
These plugins will hopefully be able to run asynchronously without intercepting
|
||||||
|
requests / responses. The idea for this is that the plugins could check for
|
||||||
|
misconfigured headers or sql statements or whatever. These won't be able to
|
||||||
|
change what the server / browser receives.
|
||||||
|
|
||||||
|
|
64
src/config.c
Normal file
64
src/config.c
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks if the given path exists by calling stat().
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static bool path_exists(const char *path) {
|
||||||
|
struct stat buf;
|
||||||
|
return (stat(path, &buf) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function resolves ~ in pathnames.
|
||||||
|
*/
|
||||||
|
static char* resolveTilde(const char *path) {
|
||||||
|
static glob_t globbuf;
|
||||||
|
|
||||||
|
int res = glob(path, GLOB_TILDE, NULL, &globbuf);
|
||||||
|
/* no match, or many wildcard matches are bad */
|
||||||
|
if (res == GLOB_NOMATCH)
|
||||||
|
return strdup(path);
|
||||||
|
else if (res != 0) {
|
||||||
|
printf("glob() failed\n");
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return strdup(globbuf.gl_pathv[0]);
|
||||||
|
}
|
||||||
|
globfree(&globbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a pointer to a config object containing defaults
|
||||||
|
*/
|
||||||
|
Config* configDefaults(){
|
||||||
|
Config *conf = malloc( sizeof( Config ) );
|
||||||
|
conf->database = "proxy.sqlite";
|
||||||
|
conf->port = 8080;
|
||||||
|
conf->localConfig = "proxy.conf";
|
||||||
|
conf->userConfig = getDefaultUserConfigLoc();
|
||||||
|
|
||||||
|
return conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* getConfigDir(){
|
||||||
|
char *xdg_config_home;
|
||||||
|
if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL)
|
||||||
|
xdg_config_home = resolveTilde("~/.config");
|
||||||
|
|
||||||
|
return xdg_config_home;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* getDefaultUserConfigLoc(){
|
||||||
|
char *configDir = getConfigDir();
|
||||||
|
char *configFile[strlen(configDir) + 11];
|
||||||
|
|
||||||
|
memset(configFile, '\0', strlen(configDir) + 11);
|
||||||
|
|
||||||
|
strcpy( configFile, configDir );
|
||||||
|
|
||||||
|
strcat( configFile, configDir );
|
||||||
|
|
||||||
|
return configFile;
|
||||||
|
}
|
||||||
|
|
24
src/config.h
Normal file
24
src/config.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H
|
||||||
|
|
||||||
|
#include <glob.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *database;
|
||||||
|
char *localConfig; // Project Specific
|
||||||
|
char *userConfig; // User Specific
|
||||||
|
unsigned int port;
|
||||||
|
} Config;
|
||||||
|
|
||||||
|
static bool path_exists(const char *path);
|
||||||
|
static char* resolveTilde(const char *path);
|
||||||
|
Config* configDefaults();
|
||||||
|
char* getConfigDir();
|
||||||
|
char* getDefaultUserConfigLoc();
|
||||||
|
|
||||||
|
#endif /* ifndef CONFIG_H */
|
46
src/database.c
Normal file
46
src/database.c
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#include "database.h"
|
||||||
|
|
||||||
|
sqlite3 *db_open(char *file){
|
||||||
|
sqlite3 *db;
|
||||||
|
/* Open database */
|
||||||
|
int rc = sqlite3_open(file, &db);
|
||||||
|
|
||||||
|
if( rc ) {
|
||||||
|
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Opened database successfully\n");
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool db_file_exists(char *file){
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if ( (fp = fopen(file, "r")) != NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool db_create(char *file){
|
||||||
|
FILE *fp = fopen(file, "a");
|
||||||
|
if(fp == NULL) {
|
||||||
|
printf("file can't be opened\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
sqlite3 *db = db_open(file);
|
||||||
|
|
||||||
|
// Do stuff here to create the tables.
|
||||||
|
// Will probably need Requests and Responses - maybe others
|
||||||
|
|
||||||
|
|
||||||
|
sqlite3_close(db);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
13
src/database.h
Normal file
13
src/database.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef DATABASE_H
|
||||||
|
#define DATABASE_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
sqlite3 *db_open(char *file);
|
||||||
|
bool db_file_exists(char *file);
|
||||||
|
//Returns true if the file was successfully created, false otherwise
|
||||||
|
bool db_create(char *file);
|
||||||
|
|
||||||
|
#endif /* ifndef LOG_H */
|
76
src/main.c
Normal file
76
src/main.c
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "database.h"
|
||||||
|
#include "proxy.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define PACKAGE_NAME "WICTP"
|
||||||
|
#define DEFAULT_DATABASE "data.sqlite"
|
||||||
|
#define DEFAULT_CONFIG "config.json"
|
||||||
|
#define DEFAULT_PORT 8080
|
||||||
|
|
||||||
|
unsigned int validatePortNumber(unsigned int portNumber){
|
||||||
|
// Given that we are dealing with unsined ints, we don't need to worry about
|
||||||
|
// checking for values less than 0
|
||||||
|
if ( portNumber > 65535 ){
|
||||||
|
printf( "Port %i is invalid, using default of %i", portNumber, DEFAULT_PORT );
|
||||||
|
return DEFAULT_PORT;
|
||||||
|
}
|
||||||
|
return portNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printHelp(){
|
||||||
|
printf("Usage: %s [options]\n", PACKAGE_NAME);
|
||||||
|
printf( "Options are:\n" );
|
||||||
|
printf( "\t --database DATABASE A sqlite3 database file (Defatult: %s)\n", DEFAULT_DATABASE );
|
||||||
|
printf( "\t --config CONFIG A config file (Default: %s)\n", DEFAULT_CONFIG );
|
||||||
|
printf( "\t --port PORT The listening port (Default: %i)\n", DEFAULT_PORT );
|
||||||
|
printf( "\t --help Display version information.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char**argv){
|
||||||
|
char *database = DEFAULT_DATABASE;
|
||||||
|
char *config = DEFAULT_CONFIG;
|
||||||
|
unsigned int port = DEFAULT_PORT;
|
||||||
|
|
||||||
|
Config *defaultconfig = configDefaults();
|
||||||
|
|
||||||
|
|
||||||
|
for ( unsigned int i = 1; i < argc; i++ ){
|
||||||
|
if ( strcmp( argv[i], "--database" ) == 0 ){
|
||||||
|
if ( i + 1 < argc ){
|
||||||
|
database = argv[++i];
|
||||||
|
} else {
|
||||||
|
printf("--database requires a positional argument\n");
|
||||||
|
}
|
||||||
|
} else if ( strcmp( argv[i], "--config" ) == 0 ){
|
||||||
|
if ( i + 1 < argc ){
|
||||||
|
config = argv[++i];
|
||||||
|
} else {
|
||||||
|
printf("--config requires a positional argument\n");
|
||||||
|
}
|
||||||
|
} else if ( strcmp( argv[i], "--port" ) == 0 ){
|
||||||
|
if ( i + 1 < argc ){
|
||||||
|
port = validatePortNumber( atoi(argv[++i]) );
|
||||||
|
} else {
|
||||||
|
printf("--port requires a positional argument\n");
|
||||||
|
}
|
||||||
|
} else if ( strcmp( argv[i], "--help" ) == 0 ){
|
||||||
|
printHelp();
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
printf("Unknown option %s\n", argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !db_file_exists(database) ){
|
||||||
|
printf("Creating DB");
|
||||||
|
db_create(database);
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy_startListener(port);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
42
src/proxy.c
Normal file
42
src/proxy.c
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "proxy.h"
|
||||||
|
|
||||||
|
void proxy_startListener(unsigned int port){
|
||||||
|
// https://www.geeksforgeeks.org/socket-programming-cc/
|
||||||
|
int server_fd, new_socket;
|
||||||
|
struct sockaddr_in address;
|
||||||
|
int opt = 1;
|
||||||
|
int addrlen = sizeof(address);
|
||||||
|
char line[1024] = {0};
|
||||||
|
|
||||||
|
// Creating socket file descriptor
|
||||||
|
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
||||||
|
perror("socket failed");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
address.sin_family = AF_INET;
|
||||||
|
address.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
address.sin_port = htons( port );
|
||||||
|
|
||||||
|
// Forcefully attaching socket to the port 8080
|
||||||
|
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
|
||||||
|
perror("bind failed");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(server_fd, 3) < 0) {
|
||||||
|
perror("listen");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
while ( true ){
|
||||||
|
printf("Listening\n");
|
||||||
|
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
|
||||||
|
(socklen_t*)&addrlen))<0) {
|
||||||
|
perror("accept");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request *request = newRequestFromSocket(new_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
src/proxy.h
Normal file
16
src/proxy.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef PROXY_H
|
||||||
|
#define PROXY_H
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
|
void proxy_startListener( unsigned int port );
|
||||||
|
|
||||||
|
#endif /* ifndef PROXY_H */
|
50
src/readline.c
Normal file
50
src/readline.c
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
// https://man7.org/tlpi/code/online/dist/sockets/read_line.c.html
|
||||||
|
#include "readline.h"
|
||||||
|
|
||||||
|
/* Read characters from 'fd' until a newline is encountered. If a newline
|
||||||
|
character is not encountered in the first (n - 1) bytes, then the excess
|
||||||
|
characters are discarded. The returned string placed in 'buf' is
|
||||||
|
null-terminated and includes the newline character if it was read in the
|
||||||
|
first (n - 1) bytes. The function return value is the number of bytes
|
||||||
|
placed in buffer (which includes the newline character if encountered,
|
||||||
|
but excludes the terminating null byte). */
|
||||||
|
ssize_t fdReadLine(int fd, void *buffer, size_t n) {
|
||||||
|
ssize_t numRead; /* # of bytes fetched by last read() */
|
||||||
|
size_t totRead; /* Total bytes read so far */
|
||||||
|
char *buf;
|
||||||
|
char ch;
|
||||||
|
if (n <= 0 || buffer == NULL) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf = buffer; /* No pointer arithmetic on "void *" */
|
||||||
|
totRead = 0;
|
||||||
|
for (;;) {
|
||||||
|
numRead = read(fd, &ch, 1);
|
||||||
|
if (numRead == -1) {
|
||||||
|
if (errno == EINTR) /* Interrupted --> restart read() */
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
return -1; /* Some other error */
|
||||||
|
|
||||||
|
} else if (numRead == 0) { /* EOF */
|
||||||
|
if (totRead == 0) /* No bytes read; return 0 */
|
||||||
|
return 0;
|
||||||
|
else /* Some bytes read; add '\0' */
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else { /* 'numRead' must be 1 if we get here */
|
||||||
|
if (totRead < n - 1) { /* Discard > (n - 1) bytes */
|
||||||
|
totRead++;
|
||||||
|
*buf++ = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*buf = '\0';
|
||||||
|
return totRead;
|
||||||
|
}
|
||||||
|
|
9
src/readline.h
Normal file
9
src/readline.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef READLINE_H
|
||||||
|
#define READLINE_H
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
ssize_t fdReadLine(int fd, void *buffer, size_t n);
|
||||||
|
|
||||||
|
#endif /* ifndef READLINE_H */
|
69
src/request.c
Normal file
69
src/request.c
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
|
Header* newHeader(char *str){
|
||||||
|
Header *header = malloc(sizeof(Header));
|
||||||
|
memset(header, 0, sizeof(Header));
|
||||||
|
|
||||||
|
int position = -1;
|
||||||
|
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < strlen(str); i++ ){
|
||||||
|
if ( str[i] == ':' ){
|
||||||
|
position = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( position == -1 ){
|
||||||
|
printf("Header without colon. Not sure what to do\n");
|
||||||
|
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 ) );
|
||||||
|
memset(header->name, '\0', position+1);
|
||||||
|
strncpy( header->name, str, position );
|
||||||
|
|
||||||
|
for ( unsigned int i = position+1; i < strlen(str); i++ ){
|
||||||
|
if ( str[i] == '\t' || str[i] == ' ' ) continue;
|
||||||
|
position = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Anything left is the value
|
||||||
|
header->value = malloc( sizeof(char) * ( strlen(str) - position ) );
|
||||||
|
memset(header->value, '\0', ( strlen(str) - position ) );
|
||||||
|
strcpy( header->value, str + position );
|
||||||
|
|
||||||
|
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request* newRequest(){
|
||||||
|
Request *request = malloc(sizeof(Request));
|
||||||
|
memset(request, 0, sizeof(Request));
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Request* newRequestFromSocket(int socket){
|
||||||
|
Request *req = newRequest();
|
||||||
|
int valread;
|
||||||
|
char line[1024] = {0};
|
||||||
|
valread = fdReadLine( socket , line, 1024);
|
||||||
|
char hello[] = "this is a test";
|
||||||
|
|
||||||
|
// The first line will give us some important information
|
||||||
|
|
||||||
|
//a length of 2 will indicate an empty line which will split the headers
|
||||||
|
//from the body (if there is a body)
|
||||||
|
while ( valread > 2 ){
|
||||||
|
printf("%s",line );
|
||||||
|
valread = fdReadLine( socket , line, 1024);
|
||||||
|
}
|
||||||
|
send(socket , hello , strlen(hello) , 0 );
|
||||||
|
printf("Hello message sent\n");
|
||||||
|
return req;
|
||||||
|
}
|
53
src/request.h
Normal file
53
src/request.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef REQUEST_H
|
||||||
|
#define REQUEST_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "readline.h"
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
typedef enum {HTTP,HTTPS} HTTPProtocol;
|
||||||
|
typedef enum {GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH} HTTPMethod;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A struct reperesenting an http header
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
// The spec doesn't specify a max size for headers, but nginx doesn't accept headers bigger than 4096 so that's probably ok for us
|
||||||
|
char *value;
|
||||||
|
} Header;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A linked list wrapper around the headers
|
||||||
|
*/
|
||||||
|
typedef struct HeaderList HeaderList;
|
||||||
|
struct HeaderList {
|
||||||
|
Header header;
|
||||||
|
HeaderList *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A struct reperesenting an http request
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
// Common versions are: 0.9, 1.0, 1.1, 2.0
|
||||||
|
double version;
|
||||||
|
HTTPMethod method;
|
||||||
|
HTTPProtocol protocol;
|
||||||
|
char *host;
|
||||||
|
char *path;
|
||||||
|
HeaderList *headers;
|
||||||
|
char *queryString;
|
||||||
|
char *body;
|
||||||
|
} Request;
|
||||||
|
|
||||||
|
Header* newHeader();
|
||||||
|
Request* newRequest();
|
||||||
|
Request* newRequestFromSocket(int socket);
|
||||||
|
void* addHeader(Request *req);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ifndef REQUEST_H */
|
Loading…
Add table
Add a link
Reference in a new issue