httptest.cpp 36 KB

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