-
Notifications
You must be signed in to change notification settings - Fork 131
/
Copy pathreplayserver.cc
176 lines (155 loc) · 6.76 KB
/
replayserver.cc
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
/* -*-mode:c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include <memory>
#include <csignal>
#include <algorithm>
#include <iostream>
#include <vector>
#include <fstream>
#include "util.hh"
#include "system_runner.hh"
#include "http_record.pb.h"
#include "http_header.hh"
#include "exception.hh"
#include "http_message.hh"
using namespace std;
/* compare specific env header value and stored header value (if either does not exist, return true) */
bool check_headers( const string & env_header, const string & stored_header, HTTP_Record::http_message & saved_req )
{
if ( getenv( env_header.c_str() ) == NULL ) {
return true;
}
string env_value;
/* environment header was passed to us */
env_value = string( getenv( env_header.c_str() ) );
for ( int i = 0; i < saved_req.headers_size(); i++ ) {
HTTPHeader current_header( saved_req.headers(i) );
if ( HTTPMessage::equivalent_strings( current_header.key(), stored_header ) ) { /* compare to environment variable */
if ( current_header.value().substr( 0, current_header.value().find( "\r\n" ) ) == getenv( env_header.c_str() ) ) {
return true;
} else {
cerr << stored_header << " does not match environment variable" << endl;
return false;
}
}
}
/* environment header not in stored header */
return true;
}
/* compare request_line and certain headers of incoming request and stored request */
bool compare_requests( HTTP_Record::reqrespair & saved_record, vector< HTTP_Record::reqrespair > & possible_matches )
{
HTTP_Record::http_message saved_req = saved_record.req();
/* request line */
string new_req = string( getenv( "REQUEST_METHOD" ) ) + " " + string( getenv( "REQUEST_URI" ) ) + " " + string ( getenv( "SERVER_PROTOCOL" ) ) + "\r\n";
uint64_t query_loc = saved_req.first_line().find( "?" );
if ( query_loc == std::string::npos ) { /* no query string: compare object name */
if ( not ( new_req == saved_req.first_line() ) ) {
return false;
}
} else { /* query string present: compare and if not match but object names matches, add to possibilities */
if ( not ( new_req == saved_req.first_line() ) ) {
string no_query = string( getenv( "REQUEST_METHOD" ) ) + " " + string( getenv( "SCRIPT_NAME" ) );
if ( no_query == saved_req.first_line().substr( 0, query_loc ) ) { /* request w/o query string matches */
possible_matches.emplace_back( saved_record );
}
return false;
}
}
/* compare existing environment variables for request to stored header values */
if ( not check_headers( "HTTP_ACCEPT_ENCODING", "Accept_Encoding", saved_req ) ) { return false; }
if ( not check_headers( "HTTP_ACCEPT_LANGUAGE", "Accept_Language", saved_req ) ) { return false; }
//if ( not check_headers( "HTTP_CONNECTION", "Connection", saved_req ) ) { return false; }
//if ( not check_headers( "HTTP_COOKIE", "Cookie", saved_req ) ) { return false; }
if ( not check_headers( "HTTP_HOST", "Host", saved_req ) ) { return false; }
//if ( not check_headers( "HTTP_REFERER", "Referer", saved_req ) ) { return false; }
//if ( not check_headers( "HTTP_USER_AGENT", "User-Agent", saved_req ) ) { return false; }
/* all compared fields match */
return true;
}
/* return size of longest substring match between two strings */
int longest_substr( const string & str1, const string & str2 )
{
/* http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Longest_common_substring#C.2B.2B */
if ( str1.empty() or str2.empty() ) {
return 0;
}
vector< int > curr (str2.size() );
vector< int > prev (str2.size() );
vector< int > swap;
int maxSubstr = 0;
for ( unsigned int i = 0; i < str1.size(); i++ ) {
for ( unsigned int j = 0; j < str2.size(); j++) {
if ( str1[ i ] != str2[ j ] ) {
curr.at( j ) = 0;
} else {
if ( i == 0 || j == 0 ) {
curr.at( j ) = 1;
} else {
curr.at( j ) = 1 + prev.at( j-1 );
}
if( maxSubstr < curr.at( j ) ) {
maxSubstr = curr.at( j );
}
}
}
swap=curr;
curr=prev;
prev=swap;
}
return maxSubstr;
}
/* return index of stored request_line with longest matching substring to current request */
int closest_match( const vector< HTTP_Record::reqrespair > & possible )
{
string req = string( getenv( "REQUEST_METHOD" ) ) + " " + string( getenv( "REQUEST_URI" ) ) + " " + string ( getenv( "SERVER_PROTOCOL" ) ) + "\r\n";
vector< int > longest_str;
for ( unsigned int i = 0; i < possible.size(); i++ ) {
string current_req = possible.at( i ).req().first_line();
longest_str.emplace_back( longest_substr( req, current_req ) );
}
vector< int >::iterator result = max_element( begin( longest_str ), end( longest_str ) );
return distance( begin( longest_str ), result );
}
/* write response to stdout (using no-parsed headers for apache ) */
void return_message( const HTTP_Record::reqrespair & record )
{
cout << record.res().first_line();
for ( int j = 0; j < record.res().headers_size(); j++ ) {
cout << record.res().headers( j );
}
cout << record.res().body() << endl;
}
int main()
{
try {
string record_folder = string( getenv( "RECORD_FOLDER" ) );
if ( check_folder_existence( record_folder ) ) {
delete_directory( record_folder );
}
/* Load incoming request in recordshell with phantomjs */
run( { "/usr/local/bin/recordshell", "/home/ravi/mahimahi/scriptphantom/", "/usr/bin/phantomjs",
"--ignore-ssl-errors=true", "--ssl-protocol=TLSv1", "/home/ravi/mahimahi/headlessload.js", getenv( "SCRIPT_URI" ) } );
/* Make bulk reply inside recorded folder */
run( { "/usr/local/bin/makebulkreply", "/home/ravi/mahimahi/scriptphantom/", getenv( "HTTP_HOST" ) } );
string bulk_file_name = record_folder + "bulkreply.proto";
std::ifstream is(bulk_file_name, std::ifstream::binary);
string str;
if (is) {
// get length of file:
is.seekg(0, is.end);
int length = is.tellg();
is.seekg(0, is.beg);
str.resize(length, ' '); // reserve space
char* begin = &*str.begin();
is.read(begin, length);
is.close();
}
cout << "HTTP/1.1 200 OK\r\n";
cout << "Content-Type: application/x-bulkreply\r\n\r\n";
cout << str;
return EXIT_SUCCESS;
} catch ( const Exception & e ) {
e.perror();
return EXIT_FAILURE;
}
}