-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindexserver.cpp
More file actions
201 lines (167 loc) · 6.72 KB
/
Copy pathindexserver.cpp
File metadata and controls
201 lines (167 loc) · 6.72 KB
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#include "serverUtils.h"
PluginObject *Plugin = nullptr;
// Root directory for the website, taken from argv[ 2 ].
// (Yes, a global variable since it never changes.)
void *Talk( void *talkSocket )
{
// TO DO: Look for a GET message, then reply with the
// requested file.
// Cast from void * to int * to recover the talk socket id
// then delete the copy passed on the heap.
int talkSocketid = *(int *)talkSocket;
delete (int *)talkSocket;
// Read the request from the socket and parse it to extract
// the action and the path, unencoding any %xx encodings.
char buffer[10240];
ssize_t bytesRead = recv(talkSocketid, buffer, sizeof(buffer) - 1, 0);
if (bytesRead <= 0) {
close(talkSocketid);
return nullptr;
}
buffer[bytesRead] = '\0';
// Parse the request
string request(buffer);
size_t firstSpace = request.find(" ");
size_t secondSpace = request.find(" ", firstSpace + 1);
if (firstSpace == npos || secondSpace == npos) {
AccessDenied(talkSocketid);
close(talkSocketid);
return nullptr;
}
string action = request.substr(0, firstSpace);
string path = request.substr(firstSpace + 1, secondSpace - firstSpace - 1);
// path = UnencodeUrlEncoding(path);
// Check to see if there's a plugin and, if there is,
// whether this is a magic path intercepted by the plugin.
// If it is intercepted, call the plugin's ProcessRequest( )
// and send whatever's returned over the socket.
if (Plugin && Plugin->MagicPath(path)) {
string response = Plugin->ProcessRequest(request);
send(talkSocketid, response.c_str(), response.length(), 0);
close(talkSocketid);
return nullptr;
}
// If it isn't intercepted, action must be "GET" and
// the path must be safe.
if (action != (string)"GET" || !SafePath(path.c_str())) {
std::cout << "Access denied" << std::endl;
AccessDenied(talkSocketid);
close(talkSocketid);
return nullptr;
}
if (path.find("/search") == 0) {
size_t queryPos = path.find("?q=");
string query;
if (queryPos != npos) {
string decoded_query = "";
query = path.substr(queryPos + 3);
for (int i = 0; i < query.size(); i++){
if(query[i] == '+'){
decoded_query.push_back(' ');
} else if (query[i] == '%' && i + 2 < query.size()) {
// Decode %XX hex escape
string hex = query.substr(i + 1, 2);
char ch = static_cast<char>(strtol(hex.c_str(), nullptr, 16));
decoded_query.push_back(ch);
i += 2;
} else {
decoded_query.push_back(query[i]);
}
}
query = decoded_query;
}
string buf = getResults(query);
// Send HTTP response
string header = (string)"HTTP/1.1 200 OK\r\n" +
(string)"Content-Type: text/html\r\n" +
(string)"Content-Length: " + to_string(buf.length()) + "\r\n" +
(string)"Connection: close\r\n\r\n";
send(talkSocketid, header.c_str(), header.length(), 0);
send(talkSocketid, buf.c_str(), buf.length(), 0);
close(talkSocketid);
return nullptr;
}
}
int main( int argc, char **argv )
{
if ( argc != 2 )
{
std::cerr << "Usage: " << argv[ 0 ] << " port " << std::endl;
return 1;
}
int port = atoi( argv[ 1 ] );
// We'll use two sockets, one for listening for new
// connection requests, the other for talking to each
// new client.
int listenSocket, talkSocket;
// Create socket address structures to go with each
// socket.
struct sockaddr_in listenAddress, talkAddress;
socklen_t talkAddressLength = sizeof( talkAddress );
memset( &listenAddress, 0, sizeof( listenAddress ) );
memset( &talkAddress, 0, sizeof( talkAddress ) );
// Fill in details of where we'll listen.
// We'll use the standard internet family of protocols.
listenAddress.sin_family = AF_INET;
// htons( ) transforms the port number from host (our)
// byte-ordering into network byte-ordering (which could
// be different).
listenAddress.sin_port = htons( port );
// INADDR_ANY means we'll accept connections to any IP
// assigned to this machine.
listenAddress.sin_addr.s_addr = htonl( INADDR_ANY );
// TO DO: Create the listenSocket, specifying that we'll r/w
// it as a stream of bytes using TCP/IP.
listenSocket = socket(AF_INET, SOCK_STREAM, 0);
if (listenSocket < 0) {
std::cerr << "Failed to create listen socket" << std::endl;
return 1;
}
// TO DO: Bind the listen socket to the IP address and protocol
// where we'd like to listen for connections.
int enable = 1;
if (setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) {
perror("setsockopt(SO_REUSEADDR) failed");
}
if (::bind(listenSocket, (struct sockaddr *)&listenAddress, sizeof(listenAddress)) < 0) {
std::cerr << "Failed to bind socket" << std::endl;
close(listenSocket);
return 1;
}
// TO DO: Begin listening for clients to connect to us.
// The second argument to listen( ) specifies the maximum
// number of connection requests that can be allowed to
// stack up waiting for us to accept them before Linux
// starts refusing or ignoring new ones.
//
// SOMAXCONN is a system-configured default maximum socket
// queue length. (Under WSL Ubuntu, it's defined as 128
// in /usr/include/x86_64-linux-gnu/bits/socket.h.)
if (listen(listenSocket, SOMAXCONN) < 0) {
std::cerr << "Failed to listen on socket" << std::endl;
close(listenSocket);
return 1;
}
// TO DO; Accept each new connection and create a thread to talk with
// the client over the new talk socket that's created by Linux
// when we accept the connection.
while (true) {
std::cout << "waiting for accept..." << std::endl;
talkSocket = accept(listenSocket, (struct sockaddr *)&talkAddress, &talkAddressLength);
if (talkSocket < 0) {
std::cerr << "Failed to accept connection" << std::endl;
continue;
}
// Create new thread to handle connection
int *socketPtr = new int(talkSocket);
pthread_t thread;
if (pthread_create(&thread, nullptr, Talk, socketPtr) != 0) {
std::cerr << "Failed to create thread" << std::endl;
delete socketPtr;
close(talkSocket);
continue;
}
pthread_detach(thread);
}
close( listenSocket );
}