/trunk/src/common/INet/GHttpUi.cpp

# · C++ · 316 lines · 274 code · 40 blank · 2 comment · 49 complexity · 6c591563d4ca6a65613cc792d8e7de1d MD5 · raw file

  1. #include "Lgi.h"
  2. #include "GHttpUi.h"
  3. #include "INet.h"
  4. #include "INetTools.h"
  5. struct GHttpServerPriv;
  6. #define LOG_HTTP 0
  7. class GHttpThread : public GThread
  8. {
  9. GSocket *s;
  10. GHttpServerPriv *p;
  11. public:
  12. GHttpThread(GSocket *sock, GHttpServerPriv *priv);
  13. int Main();
  14. };
  15. class GHttpServer_TraceSocket : public GSocket
  16. {
  17. public:
  18. void OnInformation(char *Str)
  19. {
  20. LgiTrace("%s:%i - SocketInfo: %s\n", _FL, Str);
  21. }
  22. void OnError(int ErrorCode, char *ErrorDescription)
  23. {
  24. LgiTrace("%s:%i - SocketError %i: %s\n", _FL, ErrorCode, ErrorDescription);
  25. }
  26. };
  27. struct GHttpServerPriv : public GThread
  28. {
  29. GHttpCallback *Callback;
  30. GHttpServer_TraceSocket Listen;
  31. int Port;
  32. GHttpServerPriv(GHttpCallback *cb, int port)
  33. {
  34. Callback = cb;
  35. Port = port;
  36. Run();
  37. }
  38. ~GHttpServerPriv()
  39. {
  40. Listen.Close();
  41. while (!IsExited())
  42. {
  43. LgiSleep(50);
  44. }
  45. }
  46. int Main()
  47. {
  48. #if LOG_HTTP
  49. LgiTrace("Attempting to listen on port %i...\n", Port);
  50. #endif
  51. if (!Listen.Listen(Port))
  52. {
  53. LgiTrace("%s:%i - Can't listen on port %i.\n", _FL, Port);
  54. return false;
  55. }
  56. #if LOG_HTTP
  57. LgiTrace("Listening on port %i.\n", Port);
  58. #endif
  59. while (Listen.IsOpen())
  60. {
  61. GSocket *s = new GSocket;
  62. #if LOG_HTTP
  63. LgiTrace("Accepting...\n");
  64. #endif
  65. if (Listen.Accept(s))
  66. {
  67. #if LOG_HTTP
  68. LgiTrace("Got new connection...\n");
  69. #endif
  70. new GHttpThread(s, this);
  71. }
  72. }
  73. return 0;
  74. }
  75. };
  76. GHttpThread::GHttpThread(GSocket *sock, GHttpServerPriv *priv)
  77. {
  78. s = sock;
  79. p = priv;
  80. Run();
  81. }
  82. int GHttpThread::Main()
  83. {
  84. GArray<char> Buf;
  85. int Block = 4 << 10, Used = 0, ContentLen = 0;
  86. int HeaderLen = 0;
  87. Buf.Length(Block);
  88. // Read headers...
  89. while (s->IsOpen())
  90. {
  91. if (Buf.Length() - Used < 1)
  92. Buf.Length(Buf.Length() + Block);
  93. int r = s->Read(&Buf[Used], Buf.Length()-Used, 0);
  94. #if LOG_HTTP
  95. LgiTrace("%s:%i - read=%i\n", _FL, r);
  96. #endif
  97. if (r > 0)
  98. {
  99. Used += r;
  100. }
  101. char *Eoh;
  102. if (!HeaderLen &&
  103. (Eoh = strnistr(&Buf[0], "\r\n\r\n", Used)))
  104. {
  105. // Found end of headers...
  106. HeaderLen = Eoh - &Buf[0] + 4;
  107. #if LOG_HTTP
  108. LgiTrace("%s:%i - HeaderLen=%i\n", _FL, HeaderLen);
  109. #endif
  110. char *s = InetGetHeaderField(&Buf[0], "Content-Length", HeaderLen);
  111. if (s)
  112. {
  113. ContentLen = atoi(s);
  114. #if LOG_HTTP
  115. LgiTrace("%s:%i - ContentLen=%i\n", _FL, ContentLen);
  116. #endif
  117. }
  118. else break;
  119. }
  120. if (ContentLen > 0)
  121. {
  122. if (Used >= HeaderLen + ContentLen)
  123. break;
  124. }
  125. if (r < 1)
  126. break;
  127. }
  128. Buf[Used] = 0;
  129. #if LOG_HTTP
  130. LgiTrace("%s:%i - got headers\n", _FL);
  131. #endif
  132. char *Action = &Buf[0];
  133. char *Eol = strnstr(Action, "\r\n", Used);
  134. #if LOG_HTTP
  135. LgiTrace("%s:%i - eol=%p\n", _FL, Eol);
  136. #endif
  137. if (Eol)
  138. {
  139. *Eol = 0;
  140. Eol += 2;
  141. int FirstLine = Eol - Action;
  142. char *Uri = strchr(Action, ' ');
  143. if (Uri)
  144. {
  145. *Uri++ = 0;
  146. #if LOG_HTTP
  147. LgiTrace("%s:%i - uri='%s'\n", _FL, Uri);
  148. #endif
  149. char *Protocol = strrchr(Uri, ' ');
  150. if (Protocol)
  151. {
  152. *Protocol++ = 0;
  153. #if LOG_HTTP
  154. LgiTrace("%s:%i - protocol='%s'\n", _FL, Protocol);
  155. #endif
  156. if (p->Callback)
  157. {
  158. char *Eoh = strnistr(Eol, "\r\n\r\n", Used - FirstLine);
  159. if (Eoh)
  160. *Eoh = 0;
  161. GVariant Out;
  162. int Code = p->Callback->OnRequest(Action, Uri, Eol, Eoh + 4, Out);
  163. #if LOG_HTTP
  164. LgiTrace("%s:%i - Code=%i\n", _FL, Code);
  165. #endif
  166. s->Print("HTTP/1.0 %i Ok\r\n\r\n", Code);
  167. char *Response = Out.Str();
  168. #if LOG_HTTP
  169. LgiTrace("%s:%i - Response=%p\n", _FL, Response);
  170. #endif
  171. if (Response)
  172. {
  173. int Len = strlen(Out.Str());
  174. #if LOG_HTTP
  175. LgiTrace("%s:%i - Len=%p\n", _FL, Len);
  176. #endif
  177. s->Write(Out.Str(), Len);
  178. }
  179. }
  180. }
  181. }
  182. }
  183. s->Close();
  184. DeleteObj(s);
  185. return 0;
  186. }
  187. GHttpServer::GHttpServer(GHttpCallback *cb, int port)
  188. {
  189. d = new GHttpServerPriv(cb, port);
  190. }
  191. GHttpServer::~GHttpServer()
  192. {
  193. DeleteObj(d);
  194. }
  195. char *GHttpCallback::FormDecode(char *s)
  196. {
  197. char *i = s, *o = s;
  198. while (*i)
  199. {
  200. if (*i == '+')
  201. {
  202. *o++ = ' ';
  203. i++;
  204. }
  205. else if (*i == '%')
  206. {
  207. char h[3] = {i[1], i[2], 0};
  208. *o++ = htoi(h);
  209. i += 3;
  210. }
  211. else
  212. {
  213. *o++ = *i++;
  214. }
  215. }
  216. *o = 0;
  217. return s;
  218. }
  219. char *GHttpCallback::HtmlEncode(char *s)
  220. {
  221. GStringPipe p;
  222. char *e = "<>";
  223. while (s && *s)
  224. {
  225. char *b = s;
  226. while (*s && !strchr(e, *s)) s++;
  227. if (s > b)
  228. p.Write(b, s - b);
  229. if (*s)
  230. {
  231. p.Print("&#%i;", *s);
  232. s++;
  233. }
  234. else break;
  235. }
  236. return p.NewStr();
  237. }
  238. bool GHttpCallback::ParseHtmlWithDom(GVariant &Out, GDom *Dom, char *Html)
  239. {
  240. if (!Dom || !Html)
  241. return false;
  242. GStringPipe p;
  243. for (char *s = Html; s && *s; )
  244. {
  245. char *e = stristr(s, "<?");
  246. if (e)
  247. {
  248. p.Write(s, e - s);
  249. s = e + 2;
  250. while (*s && strchr(" \t\r\n", *s)) s++;
  251. char *v = s;
  252. while (*s && (isdigit(*s) || isalpha(*s) || strchr(".[]", *s)) ) s++;
  253. char *Var = NewStr(v, s - v);
  254. while (*s && strchr(" \t\r\n", *s)) s++;
  255. if (strncmp(s, "?>", 2) == 0)
  256. {
  257. GVariant Value;
  258. if (Dom->GetValue(Var, Value))
  259. {
  260. p.Push(Value.CastString());
  261. }
  262. s += 2;
  263. }
  264. else break;
  265. }
  266. else
  267. {
  268. p.Push(s);
  269. break;
  270. }
  271. }
  272. Out.Empty();
  273. Out.Type = GV_STRING;
  274. Out.Value.String = p.NewStr();
  275. return true;
  276. }