-
Notifications
You must be signed in to change notification settings - Fork 0
/
request.c
184 lines (157 loc) · 4.92 KB
/
request.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include "request.h"
#include <stdio.h>
#include <string.h>
#include "server_defines.h"
#include "log.h"
int isspace(char c) {
if (c == ' ') {
return 1;
} else {
return 0;
}
}
int shock_parse_request(shock_request_t* req, char* reqBuffer, size_t buffSize)
{
char currentLine[1024] = "";
int parsedFirstLine = 0;
int lineChar = 0; //Counter for currentLine
//Some default values
strcpy(req->agent, "N/A");
for(int i=0;i<buffSize;i++) {
if (reqBuffer[i]!='\n') {
currentLine[lineChar] = reqBuffer[i];
lineChar++;
continue;
}
if (parsedFirstLine == 0) {
parsedFirstLine = 1;
int errorCode = shock_parse_request_firstline(req, ¤tLine, strlen(currentLine));
if (errorCode == -1) return -1;
continue;
}
int headerCode = shock_parse_request_header(req, ¤tLine, strlen(currentLine));
if (headerCode == 1) printf("Parsing done.\n");
memset(currentLine, 0, sizeof(currentLine));
lineChar=0;
}
return 0;
}
int shock_parse_request_firstline(shock_request_t* req, char* firstline, size_t lineSize)
{
char method[32] = " ";
char path[ROUTE_MAX] = " ";
char version[32] = " ";
int i = 0; // this is total counter for line
int j = 0; // this is counter for current token (method/url/version)
//Parse the method name
while(isspace(firstline[j]) == 0 && j < lineSize-1){
if (j == sizeof(method)-1) {
strcpy(req->errorMsg, "Your browser sent too long method name."); //Probably, browser won't sent invalid requests, but security is required
return -1;
}
method[j] = firstline[j];
j++;
}
//We should add null-terminator to each token
method[j] = '\0';
i = j;
j=0;
i++;
//Parse route itself
while(isspace(firstline[i]) == 0 && i < lineSize-1) {
if (j == sizeof(path)-1) {
strcpy(req->errorMsg, "Requested URL is too long.");
return -1;
}
//Issue: #5 (Prevents using /.. in path to serve files outside ServerRoot)
if (firstline[i]=='/') {
if (i+2<lineSize-1) {
if (firstline[i+1] == '.' && firstline[i+2] == '.') {
shock_log(SHOCK_WARNING, "Request denied: using /.. in URL is forbidden");
strcpy(req->errorMsg, "Using /.. in URL is forbidden");
return -1;
}
}
}
path[j] = firstline[i];
j++;
i++;
}
path[j] = '\0';
j=0;
i++;
//Parse http version
while(isspace(firstline[i]) == 0 && i < lineSize-1) {
if (j == sizeof(version)-1) {
strcpy(req->errorMsg, "Too long HTTP version token.");
return -1;
}
if (firstline[i] == '\r' || firstline[i] == '\n') break; //we should handle both cases
version[j] = firstline[i];
j++;
i++;
}
version[j] = '\0';
/*printf("Request method: %s\n", method);
printf("Request path: %s\n", path);
printf("Request version: <%s>\n", version);*/
//#############################
//Now check if request is valid
//#############################
//1.Check method
if (strcmp(method, "GET") == 0) {
req->method = HTTP_GET;
} else if (strcmp(method, "POST") == 0) {
req->method = HTTP_POST;
} else {
strcpy(req->errorMsg, "Your browser sent request with unsupported HTTP method");
return -1;
}
//We don't check route, no rules here :)
strcpy(req->route, path);
//2.Check version
if (strcmp(version, "HTTP/1.1") == 0) {
req->version = 1;
} else if (strcmp(version, "HTTP/1.0") == 0) {
req->version = 0;
} else {
strcpy(req->errorMsg, "Your browser used unsupported HTTP version in request");
return -1;
}
return 0;
}
int shock_parse_request_header(shock_request_t* req, char* line, size_t lineSize)
{
//
// YES! It is awful hard-coded check! If you have an idea how to implement this better, create a pull request
//
char token[256] = "";
int j = 0;
int phase = 0;
shock_header_t header;
for (int i=0;i<lineSize;i++) {
if (isspace(line[i]) == 1) {
continue;
}
if (line[i]==':' && phase == 0) {
strcpy(header.name, token);
memset(token, 0, sizeof(token));
phase = 1;
j = 0;
continue;
}
token[j] = line[i];
j++;
}
strcpy(header.value, token);
if (strcasecmp(header.name, "If-None-Match") == 0) {
strcpy(req->etag, header.value);
return 0;
}
if (strcasecmp(header.name, "User-Agent") == 0) {
strcpy(req->agent, header.value);
return 0;
}
//printf("[Request] Warning: unsupported header: %s\n", header.name);
return 0;
}