1 /*****************************************************************
2 |
3 | HTTP Client Test Program 2
4 |
5 | (c) 2001-2011 Gilles Boccon-Gibod
6 | Author: Gilles Boccon-Gibod (bok@bok.net)
7 |
8 ****************************************************************/
9
10 /*----------------------------------------------------------------------
11 | includes
12 +---------------------------------------------------------------------*/
13 #include "Neptune.h"
14 #include "NptDebug.h"
15
16 #define LOG_FORMAT "%30s,%3d,%8d, %8d, %8d, [%30s], %s\n"
17
18 static NPT_HttpClient::Connector* HttpConnector = NULL;
19 static NPT_TlsContext* TlsContext = NULL;
20
21 /*----------------------------------------------------------------------
22 | TestHttpGet
23 +---------------------------------------------------------------------*/
24 static void
TestHttpGet(const char * arg,bool use_http_1_1,int verbosity)25 TestHttpGet(const char* arg, bool use_http_1_1, int verbosity)
26 {
27 const char* method = NPT_HTTP_METHOD_GET;
28 if (arg && arg[0] == '@') {
29 method = NPT_HTTP_METHOD_HEAD;
30 ++arg;
31 }
32 NPT_HttpUrl url(arg);
33 NPT_HttpRequest request(url, method);
34 NPT_HttpClient client;
35 NPT_HttpResponse* response;
36
37 if (!url.IsValid()) return;
38 if (use_http_1_1) request.SetProtocol(NPT_HTTP_PROTOCOL_1_1);
39 if (HttpConnector) client.SetConnector(HttpConnector);
40
41 NPT_TimeStamp before;
42 NPT_System::GetCurrentTimeStamp(before);
43 NPT_Result result = client.SendRequest(request, response);
44 NPT_TimeStamp after;
45 NPT_System::GetCurrentTimeStamp(after);
46 NPT_UInt64 elapsed = (after-before).ToMillis();
47 if (NPT_FAILED(result)) {
48 if (verbosity >= 1) printf(LOG_FORMAT, NPT_ResultText(result), 0, 0, 0, (int)elapsed, "", arg);
49 return;
50 }
51 int loaded = -1;
52 if (!NPT_StringsEqual(method, NPT_HTTP_METHOD_HEAD)) {
53 NPT_DataBuffer payload;
54 result = response->GetEntity()->Load(payload);
55 if (NPT_SUCCEEDED(result)) {
56 loaded = (int)payload.GetDataSize();
57 }
58 } else {
59 loaded = 0;
60 }
61 const NPT_String* server = response->GetHeaders().GetHeaderValue("Server");
62 if (verbosity >= 1) {
63 NPT_LargeSize entity_size = response->GetEntity()?response->GetEntity()->GetContentLength():0;
64 printf(LOG_FORMAT, "NPT_SUCCESS", response->GetStatusCode(), loaded, (int)entity_size, (int)elapsed, server?server->GetChars():"", arg);
65 }
66
67 delete response;
68 }
69
70 /*----------------------------------------------------------------------
71 | TestHttpPost
72 +---------------------------------------------------------------------*/
73 static void
TestHttpPost(const char * arg,bool use_http_1_1,unsigned int verbosity)74 TestHttpPost(const char* arg, bool use_http_1_1, unsigned int verbosity)
75 {
76 NPT_HttpUrl url(arg);
77 NPT_HttpRequest request(url, NPT_HTTP_METHOD_POST);
78 NPT_HttpClient client;
79 NPT_HttpResponse* response;
80
81 if (!url.IsValid()) return;
82 if (use_http_1_1) request.SetProtocol(NPT_HTTP_PROTOCOL_1_1);
83
84 NPT_HttpEntity* entity = new NPT_HttpEntity();
85 entity->SetInputStream("blabla");
86 request.SetEntity(entity);
87 request.GetHeaders().SetHeader("Expect", "100-continue");
88
89 NPT_TimeStamp before;
90 NPT_System::GetCurrentTimeStamp(before);
91 NPT_Result result = client.SendRequest(request, response);
92 NPT_TimeStamp after;
93 NPT_System::GetCurrentTimeStamp(after);
94 NPT_UInt64 elapsed = (after-before).ToMillis();
95 if (NPT_FAILED(result)) {
96 if (verbosity >= 1) printf(LOG_FORMAT, NPT_ResultText(result), 0, 0, 0, (int)elapsed, "", arg);
97 return;
98 }
99 NPT_DataBuffer payload;
100 result = response->GetEntity()->Load(payload);
101 int loaded = -1;
102 if (NPT_SUCCEEDED(result)) {
103 loaded = (int)payload.GetDataSize();
104 }
105 const NPT_String* server = response->GetHeaders().GetHeaderValue("Server");
106 if (verbosity >= 1) printf(LOG_FORMAT, "NPT_SUCCESS", response->GetStatusCode(), loaded, (int)response->GetEntity()->GetContentLength(), (int)elapsed, server?server->GetChars():"", arg);
107
108 delete response;
109 }
110
111 /*----------------------------------------------------------------------
112 | ClientThread
113 +---------------------------------------------------------------------*/
114 class ClientThread : public NPT_Thread
115 {
116 public:
ClientThread(const char * name,const char * playlist,bool use_http_1_1,unsigned int loops,bool random,bool post,unsigned int sleep,unsigned int verbosity)117 ClientThread(const char* name,
118 const char* playlist,
119 bool use_http_1_1,
120 unsigned int loops,
121 bool random,
122 bool post,
123 unsigned int sleep,
124 unsigned int verbosity) :
125 m_Name(name),
126 m_Playlist(playlist),
127 m_UseHttp_1_1(use_http_1_1),
128 m_Loops(loops),
129 m_Random(random),
130 m_Post(post),
131 m_Sleep(sleep),
132 m_Verbosity(verbosity) {}
133
134 virtual void Run();
135
136 private:
137 NPT_String m_Name;
138 NPT_String m_Playlist;
139 bool m_UseHttp_1_1;
140 unsigned int m_Loops;
141 bool m_Random;
142 bool m_Post;
143 unsigned int m_Sleep;
144 unsigned int m_Verbosity;
145 };
146
147 /*----------------------------------------------------------------------
148 | ClientThread::Run
149 +---------------------------------------------------------------------*/
150 void
Run()151 ClientThread::Run()
152 {
153 NPT_DataBuffer list_buffer;
154 NPT_String list_string;
155 if (NPT_File::Exists(m_Playlist)) {
156 NPT_File::Load(m_Playlist, list_buffer);
157 list_string.Assign((const char*)list_buffer.GetData(), list_buffer.GetDataSize());
158 } else {
159 list_string = m_Playlist;
160 }
161 NPT_List<NPT_String> urls = list_string.Split("\n");
162 if (m_Verbosity >= 2) printf("urls: %d\n", urls.GetItemCount());
163 if (m_Verbosity >= 2) printf("loops: %d, random: %s, sleep: %d ms\n", m_Loops, m_Random?"true":"false", m_Sleep);
164 for (unsigned int i=0; i<m_Loops; i++) {
165 NPT_TimeStamp before;
166 NPT_System::GetCurrentTimeStamp(before);
167 for (unsigned int j=0; j<urls.GetItemCount(); j++) {
168 unsigned int choice = j;
169 if (m_Random) {
170 choice = NPT_System::GetRandomInteger()%urls.GetItemCount();
171 }
172 if (m_Post) {
173 TestHttpPost((*urls.GetItem(choice)).GetChars(), m_UseHttp_1_1, m_Verbosity);
174 } else {
175 TestHttpGet((*urls.GetItem(choice)).GetChars(), m_UseHttp_1_1, m_Verbosity);
176 }
177
178 if (m_Sleep) {
179 NPT_System::Sleep(NPT_TimeStamp(((float)m_Sleep)/1000.0f));
180 }
181 }
182 NPT_TimeStamp after;
183 NPT_System::GetCurrentTimeStamp(after);
184 float elapsed = (float)(after-before);
185 if (m_Verbosity >= 1) printf("%s [%04d] TOTAL time elapsed = %d ms\n", m_Name.GetChars(), i, (int)(elapsed*1000.0));
186 }
187 }
188
189 /*----------------------------------------------------------------------
190 | main
191 +---------------------------------------------------------------------*/
192 int
main(int argc,char ** argv)193 main(int argc, char** argv)
194 {
195 // parse args
196 --argc; ++argv;
197 bool use_http_1_1 = false;
198 unsigned int loops = 1;
199 bool random = false;
200 bool post = false;
201 unsigned int sleep = 0;
202 unsigned int threads = 1;
203 unsigned int verbosity = 1;
204 while (*argv) {
205 if (NPT_StringsEqual(*argv, "--http-1-1")) {
206 use_http_1_1 = true;
207 } else if (NPT_StringsEqual(*argv, "--loops")) {
208 NPT_ParseInteger(*++argv, loops);
209 } else if (NPT_StringsEqual(*argv, "--post")) {
210 post = true;
211 } else if (NPT_StringsEqual(*argv, "--random")) {
212 random = true;
213 } else if (NPT_StringsEqual(*argv, "--sleep")) {
214 NPT_ParseInteger(*++argv, sleep);
215 } else if (NPT_StringsEqual(*argv, "--verbosity")) {
216 NPT_ParseInteger(*++argv, verbosity);
217 } else if (NPT_StringsEqual(*argv, "--threads")) {
218 NPT_ParseInteger(*++argv, threads);
219 #if defined(NPT_CONFIG_ENABLE_TLS)
220 } else if (NPT_StringsEqual(*argv, "--no-cert-check")) {
221 TlsContext = new NPT_TlsContext(NPT_TlsContext::OPTION_VERIFY_LATER | NPT_TlsContext::OPTION_ADD_DEFAULT_TRUST_ANCHORS);
222 HttpConnector = new NPT_HttpTlsConnector(*TlsContext, NPT_HttpTlsConnector::OPTION_ACCEPT_SELF_SIGNED_CERTS | NPT_HttpTlsConnector::OPTION_ACCEPT_HOSTNAME_MISMATCH);
223 #endif
224 } else {
225 break;
226 }
227 ++argv;
228 }
229 if (*argv == NULL) {
230 fprintf(stderr, "ERROR: missing URL or list filename\n");
231 return 1;
232 }
233
234 NPT_Array<ClientThread*> cthreads;
235 cthreads.Resize(threads);
236 for (unsigned int i=0; i<threads; i++) {
237 NPT_String name = "THREAD ";
238 name += NPT_String::FromInteger(i);
239 ClientThread* thread = new ClientThread(name, *argv, use_http_1_1, loops, random, post, sleep, verbosity);
240 cthreads[i] = thread;
241 thread->Start();
242 }
243
244 for (unsigned int i=0; i<threads; i++) {
245 cthreads[i]->Wait();
246 delete cthreads[i];
247 }
248
249 delete TlsContext;
250 delete HttpConnector;
251
252 return 0;
253 }
254