httpserv.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /*
  2. ** JNetLib
  3. ** Copyright (C) 2001 Nullsoft, Inc.
  4. ** Author: Justin Frankel
  5. ** File: httpserv.cpp - JNL HTTP GET/POST serving implementation
  6. ** License: see jnetlib.h
  7. **
  8. ** This class just manages the http reply/sending, not where the data
  9. ** comes from, etc.
  10. */
  11. #include "netinc.h"
  12. #include "util.h"
  13. #include "httpserv.h"
  14. /*
  15. States for m_state:
  16. -1 error (connection closed, etc)
  17. 0 not read request yet.
  18. 1 reading headers
  19. 2 headers read, have not sent reply
  20. 3 sent reply
  21. 4 closed
  22. */
  23. JNL_HTTPServ::JNL_HTTPServ(JNL_Connection *con)
  24. {
  25. m_con=con;
  26. m_state=0;
  27. m_reply_headers=0;
  28. m_reply_string=0;
  29. m_recv_request=0;
  30. m_errstr=0;
  31. m_reply_ready=0;
  32. m_method = 0;
  33. http_ver = 0;
  34. keep_alive = 0;
  35. }
  36. JNL_HTTPServ::~JNL_HTTPServ()
  37. {
  38. free(m_recv_request);
  39. free(m_reply_string);
  40. free(m_reply_headers);
  41. free(m_errstr);
  42. free(m_method);
  43. m_con->Release();
  44. }
  45. static size_t strlen_whitespace(const char *str)
  46. {
  47. size_t size=0;
  48. while (str && *str && *str != ' ' && *str != '\r' && *str!='\n')
  49. {
  50. str++;
  51. size++;
  52. }
  53. return size;
  54. }
  55. int JNL_HTTPServ::run()
  56. { // returns: < 0 on error, 0 on connection close, 1 if reading request, 2 if reply not sent, 3 if reply sent, sending data.
  57. int cnt=0;
  58. run_again:
  59. m_con->run();
  60. if (m_con->get_state()==JNL_Connection::STATE_ERROR)
  61. {
  62. seterrstr(m_con->get_errstr());
  63. return -1;
  64. }
  65. if (m_con->get_state()==JNL_Connection::STATE_CLOSED)
  66. return 4;
  67. if (m_state == 0)
  68. {
  69. if (m_con->recv_lines_available()>0)
  70. {
  71. char *buf=(char*)malloc(m_con->recv_bytes_available()-1);
  72. m_con->recv_line(buf,m_con->recv_bytes_available()-1);
  73. free(m_recv_request);
  74. m_recv_request=(char*)malloc(strlen(buf)+2);
  75. strcpy(m_recv_request,buf);
  76. m_recv_request[strlen(m_recv_request)+1]=0;
  77. free(buf);
  78. buf=m_recv_request;
  79. while (buf && *buf) buf++;
  80. while (buf >= m_recv_request && *buf != ' ') buf--;
  81. if (strncmp(buf+1,"HTTP",4))// || strncmp(m_recv_request,"GET ",3))
  82. {
  83. seterrstr("malformed HTTP request");
  84. m_state=-1;
  85. }
  86. else
  87. {
  88. http_ver = atoi(buf+8);
  89. size_t method_len = strlen_whitespace(m_recv_request);
  90. m_method = (char *)malloc(method_len + 1);
  91. memcpy(m_method, m_recv_request, method_len);
  92. m_method[method_len]=0;
  93. m_state=1;
  94. cnt=0;
  95. if (buf >= m_recv_request) buf[0]=buf[1]=0;
  96. buf=strstr(m_recv_request,"?");
  97. if (buf)
  98. {
  99. *buf++=0; // change &'s into 0s now.
  100. char *t=buf;
  101. int stat=1;
  102. while (t && *t)
  103. {
  104. if (*t == '&' && !stat) { stat=1; *t=0; }
  105. else stat=0;
  106. t++;
  107. }
  108. }
  109. }
  110. }
  111. else if (!cnt++) goto run_again;
  112. }
  113. if (m_state == 1)
  114. {
  115. if (!cnt++ && m_con->recv_lines_available()<1) goto run_again;
  116. while (m_con->recv_lines_available()>0)
  117. {
  118. char buf[4096] = {0};
  119. m_con->recv_line(buf,4096);
  120. if (!buf[0])
  121. {
  122. m_state=2;
  123. break;
  124. }
  125. recvheaders.Add(buf);
  126. }
  127. }
  128. if (m_state == 2)
  129. {
  130. if (m_reply_ready)
  131. {
  132. // send reply
  133. m_con->send_string((char*)(m_reply_string?m_reply_string:"HTTP/1.1 200 OK"));
  134. m_con->send_string("\r\n");
  135. if (m_reply_headers) m_con->send_string(m_reply_headers);
  136. m_con->send_string("\r\n");
  137. m_state=3;
  138. }
  139. }
  140. if (m_state == 3)
  141. {
  142. // nothing.
  143. }
  144. return m_state;
  145. }
  146. const char *JNL_HTTPServ::get_request_file()
  147. {
  148. // file portion of http request
  149. if (!m_recv_request) return NULL;
  150. char *t=m_recv_request;
  151. while (t && *t && *t != ' ') t++;
  152. if (!t || !*t) return NULL;
  153. while (t && *t && *t == ' ') t++;
  154. return t;
  155. }
  156. const char *JNL_HTTPServ::get_request_parm(const char *parmname) // parameter portion (after ?)
  157. {
  158. const char *t=m_recv_request;
  159. while (t && *t) t++;
  160. if (t) t++;
  161. while (t && *t)
  162. {
  163. while (t && *t && *t == '&') t++;
  164. if (!_strnicmp(t,parmname,strlen(parmname)) && t[strlen(parmname)] == '=')
  165. {
  166. return t+strlen(parmname)+1;
  167. }
  168. t+=strlen(t)+1;
  169. }
  170. return NULL;
  171. }
  172. const char *JNL_HTTPServ::getheader(const char *headername)
  173. {
  174. return recvheaders.GetHeader(headername);
  175. }
  176. void JNL_HTTPServ::set_reply_string(const char *reply_string) // should be HTTP/1.1 OK or the like
  177. {
  178. free(m_reply_string);
  179. m_reply_string=(char*)malloc(strlen(reply_string)+1);
  180. strcpy(m_reply_string,reply_string);
  181. }
  182. void JNL_HTTPServ::add_reply_header(const char *header) // "Connection: close" for example
  183. {
  184. // if they've specified a content-length, then we can keep alive an HTTP/1.1 connection
  185. if (!keep_alive && http_ver == 1 && !_strnicmp(header, "Content-Length", 14))
  186. keep_alive = 1;
  187. if (m_reply_headers)
  188. {
  189. char *tmp=(char*)malloc(strlen(m_reply_headers)+strlen(header)+3);
  190. strcpy(tmp,m_reply_headers);
  191. strcat(tmp,header);
  192. strcat(tmp,"\r\n");
  193. free(m_reply_headers);
  194. m_reply_headers=tmp;
  195. }
  196. else
  197. {
  198. m_reply_headers=(char*)malloc(strlen(header)+3);
  199. strcpy(m_reply_headers,header);
  200. strcat(m_reply_headers,"\r\n");
  201. }
  202. }
  203. void JNL_HTTPServ::reset()
  204. {
  205. free(m_recv_request); m_recv_request = 0;
  206. free(m_reply_string); m_reply_string = 0;
  207. free(m_reply_headers); m_reply_headers = 0;
  208. free(m_errstr); m_errstr = 0;
  209. free(m_method); m_method =0;
  210. m_reply_ready=0;
  211. m_state = 0;
  212. keep_alive = 0;
  213. }