httptest.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "httptest.hpp"
  14. #include "jsocket.hpp"
  15. #include "jstream.ipp"
  16. #ifdef _WIN32
  17. #include "winsock.h"
  18. #define ERRNO() WSAGetLastError()
  19. #else
  20. #define ERRNO() (errno)
  21. #endif
  22. int httptest_tracelevel = 20;
  23. const char* sepstr = "\n---------------\n";
  24. static __int64 receiveData(ISocket* socket, IByteOutputStream* ostream, bool alwaysReadContent, const char* headersToRemove = NULL)
  25. {
  26. __int64 totalresplen = 0;
  27. if(ostream == NULL)
  28. return -1;
  29. Owned<IBufferedSocket> bsocket = createBufferedSocket(socket);
  30. if(bsocket == NULL)
  31. {
  32. printf("Can't create buffered socket\n");
  33. return -1;
  34. }
  35. //bsocket->setReadTimeout(1);
  36. char oneline[2049];
  37. int lenread = bsocket->readline(oneline, 2048, true, NULL);
  38. int content_length = 0;
  39. while(lenread >= 0 && oneline[0] != '\0' && oneline[0] != '\r' && oneline[0] != '\n')
  40. {
  41. totalresplen += lenread;
  42. if(headersToRemove != NULL)
  43. {
  44. const char* ptr = oneline;
  45. while(*ptr && *ptr != ':' && *ptr != ' ')
  46. ptr++;
  47. StringBuffer curheader;
  48. curheader.append(ptr - oneline, oneline);
  49. curheader.append(" ");
  50. if(!strstr(curheader.str(), headersToRemove))
  51. ostream->writeBytes(oneline, lenread);
  52. }
  53. else
  54. ostream->writeBytes(oneline, lenread);
  55. if(strncmp(oneline, "Content-Length:", 15) == 0)
  56. {
  57. content_length = atoi(oneline + 16);
  58. }
  59. lenread = bsocket->readline(oneline, 2048, true, NULL);
  60. }
  61. if(oneline[0] == '\r' || oneline[0] == '\n')
  62. {
  63. ostream->writeBytes(oneline, lenread);
  64. totalresplen += lenread;
  65. }
  66. if(content_length > 0)
  67. {
  68. char buf[1024 + 1];
  69. int buflen = 1024;
  70. int totallen = content_length;
  71. if(buflen > totallen)
  72. buflen = totallen;
  73. int readlen = 0;
  74. for(;;)
  75. {
  76. readlen = bsocket->read(buf, buflen);
  77. if(readlen < 0)
  78. {
  79. DBGLOG(">> socket read error %d", readlen);
  80. break;
  81. }
  82. if(readlen == 0)
  83. break;
  84. totalresplen += readlen;
  85. ostream->writeBytes(buf, readlen);
  86. totallen -= readlen;
  87. if(totallen <= 0)
  88. break;
  89. if(buflen > totallen)
  90. buflen = totallen;
  91. }
  92. }
  93. else if(alwaysReadContent)
  94. {
  95. char buf[1024 + 1];
  96. int buflen = 10;
  97. int readlen = 0;
  98. for(;;)
  99. {
  100. readlen = bsocket->read(buf, buflen);
  101. if(readlen < 0)
  102. {
  103. DBGLOG(">> socket read error %d", readlen);
  104. break;
  105. }
  106. if(readlen == 0)
  107. break;
  108. totalresplen += readlen;
  109. buf[readlen] = 0;
  110. ostream->writeBytes(buf, readlen);
  111. }
  112. }
  113. return totalresplen;
  114. }
  115. //=======================================================================================================
  116. // class HttpClient
  117. HttpClient::HttpClient(int threads, int times, FILE* ofile)
  118. {
  119. m_threads = threads;
  120. m_times = times;
  121. m_delay = 0;
  122. m_use_ssl = false;
  123. m_ofile = ofile;
  124. }
  125. HttpClient::HttpClient(int threads, int times, const char* host, int port, FILE* ofile, bool use_ssl, IPropertyTree* sslconfig)
  126. {
  127. m_threads = threads;
  128. m_times = times;
  129. m_delay = 0;
  130. m_host.append(host);
  131. m_port = port;
  132. m_ofile = ofile;
  133. m_use_ssl = use_ssl;
  134. if(use_ssl)
  135. {
  136. #ifdef _USE_OPENSSL
  137. if(sslconfig != NULL)
  138. m_ssctx.setown(createSecureSocketContextEx2(sslconfig, ClientSocket));
  139. else
  140. m_ssctx.setown(createSecureSocketContext(ClientSocket));
  141. #else
  142. throw MakeStringException(-1, "HttpClient: failure to create SSL connection to host '%s': OpenSSL not enabled in build", host);
  143. #endif
  144. }
  145. }
  146. int HttpClient::getUrl(const char* url)
  147. {
  148. if(!url || !*url || !m_times)
  149. return 0;
  150. StringBuffer protocol, user, passwd, port, path;
  151. m_host.clear();
  152. SplitURL(url, protocol, user, passwd, m_host, port, path);
  153. if(port.length() > 0)
  154. m_port = atoi(port.str());
  155. else
  156. {
  157. if(protocol.length() > 0 && stricmp(protocol.str(), "https") == 0)
  158. m_port = 443;
  159. else
  160. m_port = 80;
  161. }
  162. if(stricmp(protocol.str(), "HTTPS") == 0)
  163. m_use_ssl = true;
  164. if(m_use_ssl)
  165. {
  166. #if _USE_OPENSSL
  167. if(m_ssctx.get() == NULL)
  168. m_ssctx.setown(createSecureSocketContext(ClientSocket));
  169. #else
  170. throw MakeStringException(-1, "HttpClient: failure to create SSL socket - OpenSSL not enabled in build");
  171. #endif
  172. }
  173. StringBuffer request;
  174. request.appendf("GET %s HTTP/1.0\r\n", path.str());
  175. request.append("Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*\r\n");
  176. request.append("Accept-Language: en-us\r\n");
  177. //request.append("Accept-Encoding: gzip, deflate\r\n");
  178. request.append("User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n");
  179. request.append("Host: ").append(m_host.str());
  180. if(m_port != 80)
  181. request.appendf(":%d", m_port);
  182. request.append("\r\n");
  183. if(user.length() > 0)
  184. {
  185. StringBuffer auth, abuf;
  186. abuf.appendf("%s:%s", user.str(), passwd.str());
  187. JBASE64_Encode(abuf.str(), abuf.length(), auth, false);
  188. request.appendf("Authorization: Basic %s\r\n", auth.str());
  189. }
  190. request.append("\r\n");
  191. return sendRequest(request);
  192. }
  193. int HttpClient::sendRequest(const char* infile)
  194. {
  195. StringBuffer req;
  196. if(infile && *infile)
  197. {
  198. try
  199. {
  200. req.loadFile(infile, true);
  201. }
  202. catch(IException* e)
  203. {
  204. StringBuffer errmsg;
  205. printf("\nerror loading file %s - %s", infile, e->errorMessage(errmsg).str());
  206. return -1;
  207. }
  208. catch(...)
  209. {
  210. printf("\nerror loading file %s", infile);
  211. return -1;
  212. }
  213. }
  214. if(req.length() == 0)
  215. {
  216. if(httptest_tracelevel > 0)
  217. printf("using default request\n");
  218. req.append("GET / HTTP/1.0\r\n");
  219. req.append("Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*\r\n");
  220. req.append("Accept-Language: en-us\r\n");
  221. //req.append("Accept-Encoding: gzip, deflate\r\n");
  222. req.append("User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n");
  223. req.append("Host: ").append(m_host.str());
  224. if(m_port != 80)
  225. req.appendf(":%d", m_port);
  226. req.append("\r\n");
  227. req.append("\r\n");
  228. }
  229. return sendRequest(req);
  230. }
  231. int HttpClient::sendSoapRequest(const char* url, const char* soapaction, const char* infile)
  232. {
  233. if(!url || !*url || !infile || !*infile)
  234. return 0;
  235. StringBuffer protocol, user, passwd, port, path;
  236. m_host.clear();
  237. SplitURL(url, protocol, user, passwd, m_host, port, path);
  238. if(port.length() > 0)
  239. m_port = atoi(port.str());
  240. else
  241. {
  242. if(protocol.length() > 0 && stricmp(protocol.str(), "https") == 0)
  243. m_port = 443;
  244. else
  245. m_port = 80;
  246. }
  247. if(stricmp(protocol.str(), "HTTPS") == 0)
  248. m_use_ssl = true;
  249. if(m_use_ssl)
  250. {
  251. #ifdef _USE_OPENSSL
  252. if(m_ssctx.get() == NULL)
  253. m_ssctx.setown(createSecureSocketContext(ClientSocket));
  254. #else
  255. throw MakeStringException(-1, "HttpClient: failure to create SSL socket - OpenSSL not enabled in build");
  256. #endif
  257. }
  258. StringBuffer request;
  259. try
  260. {
  261. request.loadFile(infile, true);
  262. }
  263. catch(IException* e)
  264. {
  265. StringBuffer errmsg;
  266. printf("\nerror loading file %s - %s", infile, e->errorMessage(errmsg).str());
  267. return -1;
  268. }
  269. catch(...)
  270. {
  271. printf("\nerror loading file %s", infile);
  272. return -1;
  273. }
  274. if(request.length() == 0)
  275. {
  276. printf("input is empty\n");
  277. return -1;
  278. }
  279. const char* ptr = request.str();
  280. while(*ptr == ' ')
  281. ptr++;
  282. if(*ptr != '<')
  283. {
  284. printf("the input should be xml\n");
  285. return -1;
  286. }
  287. if(strncmp(ptr, "<?xml", 5) != 0 && strncmp(ptr, "<soap:Envelope", 14) != 0)
  288. {
  289. request.insert(0, "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2002/04/secext\"><soap:Body>");
  290. request.append("</soap:Body></soap:Envelope>");
  291. }
  292. StringBuffer headers;
  293. headers.appendf("POST %s HTTP/1.1\r\n", path.str());
  294. headers.append("Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*\r\n");
  295. headers.append("Accept-Language: en-us\r\n");
  296. headers.append("Content-Type: text/xml\r\n");
  297. if(soapaction && *soapaction)
  298. headers.appendf("SOAPAction: \"%s\"\r\n", soapaction);
  299. //headers.append("Accept-Encoding: gzip, deflate\r\n");
  300. headers.append("User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n");
  301. headers.appendf("Content-Length: %d\r\n", request.length());
  302. headers.append("Host: ").append(m_host.str());
  303. if(m_port != 80)
  304. headers.appendf(":%d", m_port);
  305. headers.append("\r\n");
  306. if(user.length() > 0)
  307. {
  308. StringBuffer auth, abuf;
  309. abuf.appendf("%s:%s", user.str(), passwd.str());
  310. JBASE64_Encode(abuf.str(), abuf.length(), auth, false);
  311. headers.appendf("Authorization: Basic %s\r\n", auth.str());
  312. }
  313. headers.append("\r\n");
  314. request.insert(0, headers.str());
  315. return sendRequest(request);
  316. }
  317. class CHttpClientThread : public Thread
  318. {
  319. private:
  320. int m_times;
  321. HttpStat m_stat;
  322. StringBuffer& m_request;
  323. HttpClient* m_client;
  324. public:
  325. CHttpClientThread(int times, HttpClient* client, StringBuffer& req): m_request(req)
  326. {
  327. m_times = times;
  328. m_client = client;
  329. }
  330. virtual int run()
  331. {
  332. if(m_client)
  333. return m_client->sendRequest(m_times, m_stat, m_request);
  334. return 0;
  335. }
  336. HttpStat& getStat()
  337. {
  338. return m_stat;
  339. }
  340. };
  341. int HttpClient::sendRequest(StringBuffer& req)
  342. {
  343. int thrds = m_threads;
  344. if(m_threads > 1)
  345. {
  346. int it_per_thrd = 1;
  347. int extra = 0;
  348. if(thrds > m_times)
  349. thrds = m_times;
  350. else
  351. {
  352. it_per_thrd = m_times / thrds;
  353. extra = m_times - it_per_thrd * thrds;
  354. }
  355. CHttpClientThread** thrdlist = new CHttpClientThread*[thrds];
  356. int i;
  357. for(i = 0; i < extra; i++)
  358. thrdlist[i] = new CHttpClientThread(it_per_thrd + 1, this, req);
  359. for(i = extra; i < thrds; i++)
  360. thrdlist[i] = new CHttpClientThread(it_per_thrd, this, req);
  361. for(i = 0; i < thrds; i++)
  362. thrdlist[i]->start();
  363. for(i = 0; i < thrds; i++)
  364. thrdlist[i]->join();
  365. for(i = 0; i < thrds; i++)
  366. {
  367. CHttpClientThread* thrd = thrdlist[i];
  368. HttpStat& stat = thrd->getStat();
  369. if(m_stat.msecs < stat.msecs)
  370. m_stat.msecs = stat.msecs;
  371. m_stat.totalreqlen += stat.totalreqlen;
  372. m_stat.totalresplen += stat.totalresplen;
  373. m_stat.numrequests += stat.numrequests;
  374. if(m_stat.fastest > stat.fastest)
  375. m_stat.fastest = stat.fastest;
  376. if(m_stat.slowest < stat.slowest)
  377. m_stat.slowest = stat.slowest;
  378. }
  379. delete [] thrdlist;
  380. }
  381. else
  382. sendRequest(m_times, m_stat, req);
  383. fprintf(m_ofile, ">> Statistics:\n");
  384. fprintf(m_ofile, "%s", sepstr);
  385. fprintf(m_ofile, "Number of threads: %d\n", thrds);
  386. m_stat.printStat(m_ofile);
  387. fprintf(m_ofile, "%s", sepstr);
  388. return 0;
  389. }
  390. int HttpClient::sendRequest(int times, HttpStat& stat, StringBuffer& req)
  391. {
  392. StringBuffer request;
  393. if(req.length() <= 2)
  394. {
  395. throw MakeStringException(-1, "request too short");
  396. }
  397. bool endofheaders = false;
  398. char c0 = req.charAt(0);
  399. char c1 = req.charAt(1);
  400. if(c0 == '\n')
  401. request.append("\r\n");
  402. else
  403. request.append(c0);
  404. if(c1 == '\n')
  405. {
  406. if(c0 == '\r')
  407. request.append(c1);
  408. else
  409. {
  410. request.append("\r\n");
  411. if(c0 == '\n')
  412. endofheaders = true;
  413. }
  414. }
  415. else
  416. request.append(c1);
  417. unsigned seq = 2;
  418. while(seq < req.length() && !endofheaders)
  419. {
  420. char c = req.charAt(seq);
  421. if(c == '\n')
  422. {
  423. char c1 = req.charAt(seq - 1);
  424. char c2 = req.charAt(seq - 2);
  425. if(c1 == '\n' || (c1 == '\r' && c2 == '\n'))
  426. endofheaders = true;
  427. if(c1 != '\r')
  428. request.append("\r\n");
  429. else
  430. request.append(c);
  431. }
  432. else
  433. request.append(c);
  434. seq++;
  435. }
  436. if(seq < req.length())
  437. request.append(req.length() - seq, req.str() + seq);
  438. if(httptest_tracelevel > 5)
  439. fprintf(m_ofile, ">>sending out request to %s:%d for %d times\n", m_host.str(), m_port, times);
  440. unsigned start = msTick();
  441. int slowest = 0;
  442. int fastest = 2147483647;
  443. for(int i = 0; i < times; i++)
  444. {
  445. SocketEndpoint ep;
  446. ep.set(m_host.str(), m_port);
  447. Owned<ISocket> socket;
  448. try
  449. {
  450. socket.setown(ISocket::connect(ep));
  451. if(m_use_ssl && m_ssctx.get() != NULL)
  452. {
  453. Owned<ISecureSocket> securesocket = m_ssctx->createSecureSocket(socket.getLink());
  454. int res = securesocket->secure_connect();
  455. if(res >= 0)
  456. {
  457. socket.set(securesocket.get());
  458. }
  459. }
  460. }
  461. catch(IException *excpt)
  462. {
  463. StringBuffer errMsg;
  464. UERRLOG("Error connecting to %s:%d - %d:%s", m_host.str(), m_port, excpt->errorCode(), excpt->errorMessage(errMsg).str());
  465. continue;
  466. }
  467. catch(...)
  468. {
  469. OERRLOG("Can't connect to %s:%d", m_host.str(), m_port);
  470. continue;
  471. }
  472. if(socket.get() == NULL)
  473. {
  474. StringBuffer urlstr;
  475. OERRLOG("Can't connect to %s", ep.getUrlStr(urlstr).str());
  476. continue;
  477. }
  478. if(m_delay > 0)
  479. sleep(m_delay);
  480. if(httptest_tracelevel > 5)
  481. fprintf(m_ofile, ">>sending out request:\n");
  482. if(httptest_tracelevel > 10)
  483. fprintf(m_ofile, "%s%s%s\n", sepstr, request.str(), sepstr);
  484. unsigned start1 = msTick();
  485. socket->write(request.str(), request.length());
  486. if(httptest_tracelevel > 5)
  487. fprintf(m_ofile, ">>receiving response:\n");
  488. StringBuffer buf;
  489. Owned<IByteOutputStream> ostream = createOutputStream(buf);
  490. stat.totalresplen += receiveData(socket.get(), ostream.get(), true);
  491. if(httptest_tracelevel > 10)
  492. fprintf(m_ofile, "%s%s%s\n", sepstr, buf.str(), sepstr);
  493. char tmpbuf[256];
  494. unsigned int sizeread;
  495. do
  496. {
  497. socket->read(tmpbuf, 0, 256, sizeread);
  498. }
  499. while(sizeread > 0);
  500. socket->shutdown();
  501. socket->close();
  502. fflush(m_ofile);
  503. unsigned end1 = msTick();
  504. int duration = end1 - start1;
  505. if(duration <= fastest)
  506. fastest = duration;
  507. if(duration > slowest)
  508. slowest = duration;
  509. if(i % 100 == 0)
  510. fprintf(stderr, "sent out %d\n", i);
  511. }
  512. unsigned end = msTick();
  513. stat.msecs = end - start;
  514. stat.numrequests = times;
  515. stat.totalreqlen = times * request.length();
  516. stat.slowest = slowest;
  517. stat.fastest = fastest;
  518. return 0;
  519. }
  520. void HttpClient::setDelay(int secs)
  521. {
  522. m_delay = secs;
  523. }
  524. //=======================================================================================================
  525. // class HttpServer
  526. HttpServer::HttpServer(int port, const char* in, FILE* ofile, bool use_ssl, IPropertyTree* sslconfig)
  527. {
  528. m_ifname.append(in);
  529. m_port = port;
  530. m_ofile = ofile;
  531. m_use_ssl = use_ssl;
  532. m_recvDelay = m_sendDelay = m_closeDelay = 0;
  533. if(use_ssl)
  534. {
  535. #ifdef _USE_OPENSSL
  536. if(sslconfig != NULL)
  537. m_ssctx.setown(createSecureSocketContextEx2(sslconfig, ServerSocket));
  538. else
  539. m_ssctx.setown(createSecureSocketContext(ServerSocket));
  540. #else
  541. throw MakeStringException(-1, "HttpServer: failure to create SSL socket - OpenSSL not enabled in build");
  542. #endif
  543. }
  544. }
  545. int HttpServer::start()
  546. {
  547. if(m_ifname.length() > 0)
  548. {
  549. try
  550. {
  551. m_response.loadFile(m_ifname.str(), true);
  552. }
  553. catch(IException* e)
  554. {
  555. StringBuffer errmsg;
  556. printf("\nerror loading file %s - %s", m_ifname.str(), e->errorMessage(errmsg).str());
  557. }
  558. catch(...)
  559. {
  560. printf("\nerror loading file %s", m_ifname.str());
  561. }
  562. }
  563. Owned<ISocket> socket = ISocket::create(m_port);
  564. if(httptest_tracelevel > 0)
  565. printf("Server started\n");
  566. for (;;)
  567. {
  568. Owned<ISocket> client = socket->accept();
  569. // use ssl?
  570. if(m_use_ssl && m_ssctx.get() != NULL)
  571. {
  572. try
  573. {
  574. Owned<ISecureSocket> secure_sock = m_ssctx->createSecureSocket(client.getLink());
  575. int res = secure_sock->secure_accept();
  576. if(res < 0)
  577. {
  578. printf("secure_accept error\n");
  579. continue;
  580. }
  581. client.set(secure_sock.get());
  582. }
  583. catch(...)
  584. {
  585. printf("secure_accept error\n");
  586. continue;
  587. }
  588. }
  589. // handle the request
  590. try
  591. {
  592. handleOneRequest(client);
  593. } catch (IException* e) {
  594. StringBuffer msg;
  595. IERRLOG("Exception occured: %s", e->errorMessage(msg).str());
  596. e->Release();
  597. } catch (...) {
  598. IERRLOG("Unknown exception occurred");
  599. }
  600. }
  601. return 0;
  602. }
  603. void HttpServer::handleOneRequest(ISocket* client)
  604. {
  605. char peername[256];
  606. int port = client->peer_name(peername, 256);
  607. if(httptest_tracelevel > 5)
  608. fprintf(m_ofile, "\n>>receivd request from %s:%d\n", peername, port);
  609. StringBuffer requestbuf;
  610. Owned<IByteOutputStream> reqstream = createOutputStream(requestbuf);
  611. if (m_recvDelay>0)
  612. sleep(m_recvDelay);
  613. receiveData(client, reqstream.get(), false);
  614. if(httptest_tracelevel > 10)
  615. fprintf(m_ofile, "%s%s%s", sepstr, requestbuf.str(), sepstr);
  616. if(m_response.length() == 0)
  617. {
  618. //const char* resp_body = "<html><head><meta http-equiv=\"refresh\" content=\"3; url=http://ymaxp:8020\"/></head><body>Default response from httptest server mode</body></html>";
  619. //const char* resp_body = "<html><body onLoad=window.setTimeout(\"location.href='http://ymaxp:8020'\",10000)>Default response from httptest server mode</body></html>";
  620. const char* resp_body = "<html><head><title>default response</title></head><body>Default response from httptest server mode</body></html>";
  621. //const char* resp_body = "<html><head><title>default response</title></head><body><IFRAME SRC=\"http://www.yahoo.com\" TITLE=\"esp config xml file\" width=\"100%\" height=\"100%\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\"></IFrame></body></html>";
  622. m_response.append("HTTP/1.1 200 OK\r\n");
  623. m_response.append("Content-Type: text/html; charset=UTF-8\r\n");
  624. m_response.appendf("Content-Length: %d\r\n", (int) strlen(resp_body));
  625. m_response.appendf("Subject: my-title\r\n");
  626. m_response.append("Expires: 0\r\n");
  627. m_response.append("\r\n");
  628. m_response.append(resp_body);
  629. }
  630. if (m_sendDelay)
  631. sleep(m_sendDelay);
  632. client->write(m_response.str(), m_response.length());
  633. if(httptest_tracelevel > 10)
  634. fprintf(m_ofile, "\n>>sent back response - \n");
  635. if(httptest_tracelevel > 10)
  636. fprintf(m_ofile, "%s%s%s\n", sepstr, m_response.str(), sepstr);
  637. fflush(m_ofile);
  638. if (m_closeDelay)
  639. sleep(m_closeDelay);
  640. client->close();
  641. }
  642. void replaceHeader(StringBuffer& buf, const char* name, const char* value)
  643. {
  644. StringBuffer newbuf;
  645. const char* hdr = strstr(buf.str(), StringBuffer(name).append(":").str());
  646. if(hdr)
  647. {
  648. newbuf.append(hdr - buf.str(), buf.str());
  649. newbuf.append(name).append(": ").append(value);
  650. const char* eol = strstr(hdr, "\r");
  651. if(eol)
  652. {
  653. newbuf.append(eol);
  654. }
  655. buf.swapWith(newbuf);
  656. }
  657. }
  658. void checkContentLength(StringBuffer& buf)
  659. {
  660. const char* clen = strstr(buf.str(), "Content-Length:");
  661. if(!clen)
  662. clen = strstr(buf.str(), "Content-length:");
  663. if(!clen)
  664. clen = strstr(buf.str(), "content-length:");
  665. if(!clen)
  666. {
  667. printf("no Content-Length header\n");
  668. return;
  669. }
  670. clen += 15;
  671. while(*clen && !isdigit(*clen))
  672. {
  673. clen++;
  674. }
  675. int len = 0;
  676. while(*clen && isdigit(*clen))
  677. {
  678. char c = *clen;
  679. len = len*10 + (c - '0');
  680. clen++;
  681. }
  682. printf("Content-Length is %d\n", len);
  683. const char* ptr = clen;
  684. while(*ptr)
  685. {
  686. ptr = strchr(ptr, '\n');
  687. if(!ptr)
  688. break;
  689. ptr++;
  690. if(*ptr == '\n')
  691. {
  692. ptr++;
  693. break;
  694. }
  695. else if(*(ptr+1) == '\n')
  696. {
  697. ptr += 2;
  698. break;
  699. }
  700. }
  701. int actual_len = 0;
  702. if(ptr)
  703. {
  704. actual_len = buf.length() - (ptr - buf.str());
  705. }
  706. printf("Actual length of content is %d\n", actual_len);
  707. }
  708. //=======================================================================================================
  709. // class COneServerHttpProxyThread
  710. COneServerHttpProxyThread::COneServerHttpProxyThread(ISocket* client, const char* host, int port, FILE* ofile, bool use_ssl, ISecureSocketContext* ssctx)
  711. {
  712. m_client.set(client);
  713. m_host.append(host);
  714. m_port = port;
  715. m_ofile = ofile;
  716. m_use_ssl = use_ssl;
  717. m_ssctx = ssctx;
  718. }
  719. int COneServerHttpProxyThread::start()
  720. {
  721. try
  722. {
  723. char peername[256];
  724. int port = m_client->peer_name(peername, 256);
  725. if(httptest_tracelevel > 5)
  726. fprintf(m_ofile, "\n>>receivd request from %s:%d\n", peername, port);
  727. StringBuffer requestbuf;
  728. Owned<IByteOutputStream> reqstream = createOutputStream(requestbuf);
  729. receiveData(m_client, reqstream.get(), false);
  730. if(httptest_tracelevel > 10)
  731. fprintf(m_ofile, "%s%s%s", sepstr, requestbuf.str(), sepstr);
  732. SocketEndpoint ep;
  733. Owned<ISocket> socket2;
  734. ep.set(m_host.str(), m_port);
  735. socket2.setown(ISocket::connect(ep));
  736. if(m_use_ssl && m_ssctx != NULL)
  737. {
  738. Owned<ISecureSocket> securesocket = m_ssctx->createSecureSocket(socket2.getLink());
  739. int res = securesocket->secure_connect();
  740. if(res >= 0)
  741. {
  742. socket2.set(securesocket.get());
  743. }
  744. }
  745. if(socket2.get() == NULL)
  746. {
  747. StringBuffer urlstr;
  748. OERRLOG("Can't connect to %s", ep.getUrlStr(urlstr).str());
  749. return -1;
  750. }
  751. char newhost[1024];
  752. sprintf(newhost, "%s:%d", m_host.str(), m_port);
  753. replaceHeader(requestbuf, "Host", newhost);
  754. //checkContentLength(requestbuf);
  755. if(httptest_tracelevel > 5)
  756. fprintf(m_ofile, "\n>>sending request to %s:%d\n", m_host.str(), m_port);
  757. if(httptest_tracelevel > 10)
  758. fprintf(m_ofile, "%s%s%s", sepstr, requestbuf.str(), sepstr);
  759. socket2->write(requestbuf.str(), requestbuf.length());
  760. StringBuffer respbuf;
  761. Owned<IByteOutputStream> respstream = createOutputStream(respbuf);
  762. receiveData(socket2.get(), respstream.get(), true);
  763. if(httptest_tracelevel > 5)
  764. fprintf(m_ofile, ">>received response from %s:%d:\n", m_host.str(), m_port);
  765. if(httptest_tracelevel > 10)
  766. fprintf(m_ofile, "%s%s%s", sepstr, respbuf.str(), sepstr);
  767. m_client->write(respbuf.str(), respbuf.length());
  768. fflush(m_ofile);
  769. if(httptest_tracelevel > 5)
  770. fprintf(m_ofile, ">>sent the response back to %s:%d:\n", peername, port);
  771. socket2->shutdown();
  772. socket2->close();
  773. m_client->shutdown();
  774. m_client->close();
  775. }
  776. catch(IException *excpt)
  777. {
  778. StringBuffer errMsg;
  779. OERRLOG("%s", excpt->errorMessage(errMsg).str());
  780. return -1;
  781. }
  782. catch(...)
  783. {
  784. OERRLOG("unknown exception");
  785. return -1;
  786. }
  787. return 0;
  788. }
  789. class CReadWriteThread : public Thread
  790. {
  791. private:
  792. ISocket* m_r;
  793. ISocket* m_w;
  794. public:
  795. CReadWriteThread(ISocket* r, ISocket* w)
  796. {
  797. m_r = r;
  798. m_w = w;
  799. }
  800. virtual int run()
  801. {
  802. char buf[2049];
  803. int readlen = 0;
  804. do
  805. {
  806. readlen = recv(m_r->OShandle(), buf, 2048, 0);
  807. if(readlen > 0)
  808. {
  809. buf[readlen] = 0;
  810. m_w->write(buf, readlen);
  811. }
  812. else
  813. {
  814. m_w->shutdown();
  815. m_w->close();
  816. break;
  817. }
  818. }
  819. while(true);
  820. return 0;
  821. }
  822. };
  823. //=======================================================================================================
  824. // class CHttpProxyThread
  825. CHttpProxyThread::CHttpProxyThread(ISocket* client, FILE* ofile)
  826. {
  827. m_client.set(client);
  828. m_ofile = ofile;
  829. }
  830. void CHttpProxyThread::start()
  831. {
  832. Thread::start();
  833. }
  834. int CHttpProxyThread::run()
  835. {
  836. Thread::Link();
  837. int ret = 0;
  838. try
  839. {
  840. char peername[256];
  841. int clientport = m_client->peer_name(peername, 256);
  842. if(httptest_tracelevel > 5)
  843. fprintf(m_ofile, "\n>>receivd request from %s:%d\n", peername, clientport);
  844. char oneline[2049];
  845. memset(oneline, 0, 2049);
  846. bool socketclosed = false;
  847. int lenread = readline(m_client.get(), oneline, 2048, socketclosed);
  848. if(httptest_tracelevel > 40)
  849. printf("firstline=%s\n", oneline);
  850. if(strncmp(oneline, "CONNECT ", 8) == 0)
  851. {
  852. char* curptr = oneline + 8;
  853. while(*curptr && *curptr == ' ')
  854. curptr++;
  855. const char* hostptr = curptr;
  856. while(*curptr && *curptr != ':' && *curptr != ' ')
  857. curptr++;
  858. int port = 80;
  859. if(*curptr == ':')
  860. {
  861. *curptr = 0;
  862. curptr++;
  863. const char* portptr = curptr;
  864. while(*curptr && *curptr != ' ')
  865. curptr++;
  866. *curptr = 0;
  867. if(*portptr)
  868. port = atoi(portptr);
  869. }
  870. StringBuffer host(hostptr);
  871. while(lenread > 2 && !socketclosed)
  872. lenread = readline(m_client.get(), oneline, 2048, socketclosed);
  873. SocketEndpoint ep;
  874. ep.set(host.str(), port);
  875. m_remotesocket.setown(ISocket::connect(ep));
  876. const char* resp = "HTTP/1.0 200 Connection established\r\n"
  877. "Proxy-agent: Netscape-Proxy/1.1\r\n\r\n";
  878. m_client->write(resp, strlen(resp));
  879. m_client->set_nonblock(false);
  880. m_remotesocket->set_nonblock(false);
  881. CReadWriteThread t1(m_client.get(), m_remotesocket.get());
  882. CReadWriteThread t2(m_remotesocket.get(), m_client.get());
  883. t1.start();
  884. t2.start();
  885. t1.join();
  886. t2.join();
  887. //printf("read/write threads returned\n");
  888. m_remotesocket->shutdown();
  889. m_remotesocket->close();
  890. m_client->shutdown();
  891. m_client->close();
  892. }
  893. else
  894. {
  895. const char* http = strstr(oneline, "http://");
  896. if(!http)
  897. http = strstr(oneline, "HTTP://");
  898. if(!http)
  899. throw MakeStringException(-1, "protocol not recognized\n");
  900. StringBuffer requestbuf;
  901. requestbuf.append(http - oneline, oneline);
  902. const char* slash = http + 7;
  903. while(*slash && *slash != '/' && *slash != ' ' && *slash != '\r')
  904. slash++;
  905. if(*slash != '/')
  906. requestbuf.append('/');
  907. else
  908. requestbuf.append(slash);
  909. Owned<IByteOutputStream> reqstream = createOutputStream(requestbuf);
  910. receiveData(m_client, reqstream.get(), false, "Proxy-Connection");
  911. if(httptest_tracelevel > 40)
  912. printf("%s\n", requestbuf.str());
  913. const char* hostname = http + 7;
  914. char* ptr = (char*)hostname;
  915. while(*ptr && *ptr != ':' && *ptr != '/' && *ptr != ' ')
  916. ptr++;
  917. int port = 80;
  918. if(*ptr == ':')
  919. {
  920. *ptr = 0;
  921. ptr++;
  922. const char* portptr = ptr;
  923. while(*ptr && *ptr != ' ' && *ptr != '/')
  924. ptr++;
  925. if(*ptr)
  926. *ptr = 0;
  927. if(portptr)
  928. port = atoi(portptr);
  929. }
  930. else
  931. *ptr = 0;
  932. SocketEndpoint ep;
  933. ep.set(hostname, port);
  934. m_remotesocket.setown(ISocket::connect(ep));
  935. if(httptest_tracelevel > 5)
  936. fprintf(m_ofile, ">>sending request to %s:%d\n", hostname, port);
  937. m_remotesocket->write(requestbuf.str(), requestbuf.length());
  938. StringBuffer respbuf;
  939. Owned<CSocketOutputStream> respstream = new CSocketOutputStream(m_client.get());
  940. receiveData(m_remotesocket.get(), respstream.get(), true);
  941. if(httptest_tracelevel > 5)
  942. fprintf(m_ofile, ">>receivd response from %s:%d, and sent back to %s:%d:\n", hostname, port, peername, clientport);
  943. //fprintf(m_ofile, "%s", respbuf.str());
  944. //m_client->write(respbuf.str(), respbuf.length());
  945. fflush(m_ofile);
  946. m_remotesocket->shutdown();
  947. m_remotesocket->close();
  948. m_client->shutdown();
  949. m_client->close();
  950. }
  951. }
  952. catch(IException *excpt)
  953. {
  954. StringBuffer errMsg;
  955. IERRLOG("%s", excpt->errorMessage(errMsg).str());
  956. ret = -1;
  957. }
  958. catch(...)
  959. {
  960. IERRLOG("unknown exception");
  961. ret = -1;
  962. }
  963. Thread::Release();
  964. return 0;
  965. }
  966. int CHttpProxyThread::readline(ISocket* socket, char* buf, int bufsize, bool& socketclosed)
  967. {
  968. socketclosed = false;
  969. if(!socket || !buf)
  970. return 0;
  971. char charbuf[2];
  972. int ptr = 0;
  973. try
  974. {
  975. unsigned int readlen;
  976. socket->read(charbuf,0, 1, readlen);
  977. while(readlen > 0)
  978. {
  979. if(ptr >= bufsize)
  980. {
  981. buf[ptr] = 0;
  982. return ptr;
  983. }
  984. buf[ptr++] = charbuf[0];
  985. if(charbuf[0] == '\r')
  986. {
  987. socket->read(charbuf,0, 1, readlen);
  988. if(readlen > 0 && ptr < bufsize)
  989. buf[ptr++] = charbuf[0];
  990. break;
  991. }
  992. else if(charbuf[0] == '\n')
  993. break;
  994. socket->read(charbuf,0, 1, readlen);
  995. }
  996. }
  997. catch (IException *e)
  998. {
  999. StringBuffer estr;
  1000. if(e->errorCode() != JSOCKERR_graceful_close)
  1001. {
  1002. OERRLOG("socket(%d) : %s", socket->OShandle(), e->errorMessage(estr).str());
  1003. }
  1004. e->Release();
  1005. socketclosed = true;
  1006. }
  1007. catch(...)
  1008. {
  1009. OERRLOG("Unknown exception reading from socket(%d).", socket->OShandle());
  1010. socketclosed = true;
  1011. }
  1012. buf[ptr] = 0;
  1013. return ptr;
  1014. }
  1015. //=======================================================================================================
  1016. // class HttpProxy
  1017. HttpProxy::HttpProxy(int localport, const char* host, int port, FILE* ofile, bool use_ssl, IPropertyTree* sslconfig)
  1018. {
  1019. m_localport = localport;
  1020. m_host.append(host);
  1021. m_port = port;
  1022. m_ofile = ofile;
  1023. m_use_ssl = use_ssl;
  1024. if(use_ssl)
  1025. {
  1026. #if _USE_OPENSSL
  1027. if(sslconfig != NULL)
  1028. m_ssctx.setown(createSecureSocketContextEx2(sslconfig, ClientSocket));
  1029. else
  1030. m_ssctx.setown(createSecureSocketContext(ClientSocket));
  1031. #else
  1032. throw MakeStringException(-1, "HttpProxy: failure to create SSL connection to host '%s': OpenSSL not enabled in build", host);
  1033. #endif
  1034. }
  1035. }
  1036. int HttpProxy::start()
  1037. {
  1038. Owned<ISocket> socket1 = ISocket::create(m_localport);
  1039. if(httptest_tracelevel > 0)
  1040. printf("Proxy started\n");
  1041. for (;;)
  1042. {
  1043. try
  1044. {
  1045. Owned<ISocket> client = socket1->accept();
  1046. char peername[256];
  1047. int port = client->peer_name(peername, 256);
  1048. if(m_host.length() > 0)
  1049. {
  1050. COneServerHttpProxyThread thrd(client.get(), m_host.str(), m_port, m_ofile, m_use_ssl, m_ssctx);
  1051. thrd.start();
  1052. }
  1053. else
  1054. {
  1055. Owned<CHttpProxyThread> thrd = new CHttpProxyThread(client.get(), m_ofile);
  1056. thrd->start();
  1057. }
  1058. }
  1059. catch(IException *excpt)
  1060. {
  1061. StringBuffer errMsg;
  1062. OERRLOG("%s", excpt->errorMessage(errMsg).str());
  1063. }
  1064. catch(...)
  1065. {
  1066. IERRLOG("unknown exception");
  1067. }
  1068. }
  1069. return 0;
  1070. }
  1071. #define URL_MAX 2048
  1072. void SplitURL(const char* url, StringBuffer& protocol,StringBuffer& UserName,StringBuffer& Password,StringBuffer& host, StringBuffer& port, StringBuffer& path)
  1073. {
  1074. int protlen = 0;
  1075. if(!url || strlen(url) <= 7)
  1076. throw MakeStringException(-1, "Invalid URL %s", url);
  1077. else if(strncmp(url, "HTTP://", 7) == 0 || strncmp(url, "http://", 7) == 0)
  1078. {
  1079. protocol.append("HTTP");
  1080. protlen = 7;
  1081. }
  1082. else if(strncmp(url, "HTTPS://", 8) == 0 || strncmp(url, "https://", 8) == 0)
  1083. {
  1084. protocol.append("HTTPS");
  1085. protlen = 8;
  1086. }
  1087. else
  1088. {
  1089. protocol.append("HTTP");
  1090. protlen = 0;
  1091. }
  1092. char buf[URL_MAX+1];
  1093. strncpy(buf, url, URL_MAX);
  1094. buf[URL_MAX] = 0;
  1095. char* hostptr;
  1096. char *username = NULL;
  1097. char* atsign = strrchr(buf, '@');
  1098. if(atsign)
  1099. {
  1100. username = buf + protlen;
  1101. hostptr = atsign + 1;
  1102. *atsign = '\0';
  1103. }
  1104. else
  1105. {
  1106. hostptr = buf + protlen;
  1107. }
  1108. char* pathptr = strchr(hostptr, '/');
  1109. if(pathptr)
  1110. {
  1111. *pathptr = 0;
  1112. pathptr++;
  1113. }
  1114. char* portptr = strchr(hostptr, ':');
  1115. if(portptr)
  1116. {
  1117. *portptr = 0;
  1118. portptr++;
  1119. }
  1120. if(username)
  1121. {
  1122. char* semicln = strchr(username, ':');
  1123. if(semicln)
  1124. {
  1125. Password.append(semicln+1);
  1126. *semicln = '\0';
  1127. }
  1128. UserName.append(username);
  1129. }
  1130. host.append(hostptr);
  1131. if(portptr)
  1132. port.append(portptr);
  1133. path.append("/");
  1134. if(pathptr)
  1135. path.append(pathptr);
  1136. }