httpuserv.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. ** JNetLib
  3. ** Copyright (C) 2012 Nullsoft, Inc.
  4. ** Author: Ben Allison
  5. ** File: httpuserv.cpp - JNL HTTPU (HTTP over UDP) serving implementation
  6. ** License: see jnetlib.h
  7. */
  8. #include "netinc.h"
  9. #include "util.h"
  10. #include "httpuserv.h"
  11. #include "foundation/error.h"
  12. /*
  13. States for m_state:
  14. -1 error (connection closed, etc)
  15. 0 not read request yet.
  16. 1 reading headers
  17. 2 headers read, have not sent reply
  18. 3 sent reply
  19. 4 closed
  20. */
  21. JNL_HTTPUServ::JNL_HTTPUServ()
  22. {
  23. m_reply_headers=0;
  24. m_reply_string=0;
  25. m_recv_request=0;
  26. m_errstr=0;
  27. m_reply_ready=0;
  28. m_method = 0;
  29. http_ver = 0;
  30. }
  31. JNL_HTTPUServ::~JNL_HTTPUServ()
  32. {
  33. free(m_recv_request);
  34. free(m_reply_string);
  35. free(m_reply_headers);
  36. free(m_errstr);
  37. free(m_method);
  38. }
  39. static size_t strlen_whitespace(const char *str)
  40. {
  41. size_t size=0;
  42. while (str && *str && *str != ' ' && *str != '\r' && *str!='\n')
  43. {
  44. str++;
  45. size++;
  46. }
  47. return size;
  48. }
  49. int JNL_HTTPUServ::process(JNL_UDPConnection *m_con)
  50. { // returns: < 0 on error, 0 on connection close, 1 if reading request, 2 if reply not sent, 3 if reply sent, sending data.
  51. reset();
  52. if (m_con->get_state()==JNL_CONNECTION_STATE_ERROR)
  53. {
  54. seterrstr(m_con->get_errstr());
  55. return -1;
  56. }
  57. if (m_con->get_state()==JNL_CONNECTION_STATE_CLOSED)
  58. return 4;
  59. if (m_con->recv_lines_available()>0)
  60. {
  61. char *buf=(char*)malloc(m_con->recv_bytes_available()-1);
  62. m_con->recv_line(buf,m_con->recv_bytes_available()-1);
  63. free(m_recv_request);
  64. m_recv_request=(char*)malloc(strlen(buf)+2);
  65. strcpy(m_recv_request,buf);
  66. m_recv_request[strlen(m_recv_request)+1]=0;
  67. free(buf);
  68. buf=m_recv_request;
  69. while (buf && *buf) buf++;
  70. while (buf >= m_recv_request && *buf != ' ') buf--;
  71. if (strncmp(buf+1,"HTTP",4))// || strncmp(m_recv_request,"GET ",3))
  72. {
  73. seterrstr("malformed HTTP request");
  74. }
  75. else
  76. {
  77. http_ver = atoi(buf+8);
  78. size_t method_len = strlen_whitespace(m_recv_request);
  79. m_method = (char *)malloc(method_len + 1);
  80. if (m_method)
  81. {
  82. memcpy(m_method, m_recv_request, method_len);
  83. m_method[method_len]=0;
  84. }
  85. else
  86. {
  87. seterrstr("malformed HTTP request");
  88. return -1;
  89. }
  90. if (buf >= m_recv_request) buf[0]=buf[1]=0;
  91. buf=strstr(m_recv_request,"?");
  92. if (buf)
  93. {
  94. *buf++=0; // change &'s into 0s now.
  95. char *t=buf;
  96. int stat=1;
  97. while (t && *t)
  98. {
  99. if (*t == '&' && !stat) { stat=1; *t=0; }
  100. else stat=0;
  101. t++;
  102. }
  103. }
  104. }
  105. }
  106. else
  107. {
  108. seterrstr("malformed HTTP request");
  109. return -1;
  110. }
  111. while (m_con->recv_lines_available()>0)
  112. {
  113. char buf[8192] = {0};
  114. m_con->recv_line(buf, 8192);
  115. if (!buf[0])
  116. break;
  117. recvheaders.Add(buf);
  118. }
  119. return NErr_Success;
  120. }
  121. void JNL_HTTPUServ::send_reply(JNL_UDPConnection *m_con)
  122. {
  123. m_con->send_string((char*)(m_reply_string?m_reply_string:"HTTP/1.1 200 OK"));
  124. m_con->send_string("\r\n");
  125. if (m_reply_headers) m_con->send_string(m_reply_headers);
  126. m_con->send_string("\r\n");
  127. }
  128. const char *JNL_HTTPUServ::get_request_uri()
  129. {
  130. // file portion of http request
  131. if (!m_recv_request) return NULL;
  132. char *t=m_recv_request;
  133. while (t && *t && *t != ' ') t++;
  134. if (!t || !*t) return NULL;
  135. while (t && *t && *t == ' ') t++;
  136. return t;
  137. }
  138. const char *JNL_HTTPUServ::get_request_parm(const char *parmname) // parameter portion (after ?)
  139. {
  140. const char *t=m_recv_request;
  141. while (*t) t++;
  142. t++;
  143. while (t && *t)
  144. {
  145. while (t && *t && *t == '&') t++;
  146. if (!strncasecmp(t,parmname,strlen(parmname)) && t[strlen(parmname)] == '=')
  147. {
  148. return t+strlen(parmname)+1;
  149. }
  150. t+=strlen(t)+1;
  151. }
  152. return NULL;
  153. }
  154. const char *JNL_HTTPUServ::getheader(const char *headername)
  155. {
  156. return recvheaders.GetHeader(headername);
  157. }
  158. void JNL_HTTPUServ::set_reply_string(const char *reply_string) // should be HTTP/1.1 OK or the like
  159. {
  160. free(m_reply_string);
  161. m_reply_string=(char*)malloc(strlen(reply_string)+1);
  162. strcpy(m_reply_string,reply_string);
  163. }
  164. void JNL_HTTPUServ::set_reply_header(const char *header) // "Connection: close" for example
  165. {
  166. if (m_reply_headers)
  167. {
  168. char *tmp=(char*)malloc(strlen(m_reply_headers)+strlen(header)+3);
  169. strcpy(tmp,m_reply_headers);
  170. strcat(tmp,header);
  171. strcat(tmp,"\r\n");
  172. free(m_reply_headers);
  173. m_reply_headers=tmp;
  174. }
  175. else
  176. {
  177. m_reply_headers=(char*)malloc(strlen(header)+3);
  178. strcpy(m_reply_headers,header);
  179. strcat(m_reply_headers,"\r\n");
  180. }
  181. }
  182. void JNL_HTTPUServ::reset()
  183. {
  184. free(m_recv_request); m_recv_request = 0;
  185. free(m_reply_string); m_reply_string = 0;
  186. free(m_reply_headers); m_reply_headers = 0;
  187. free(m_errstr); m_errstr = 0;
  188. free(m_method); m_method =0;
  189. recvheaders.Reset();
  190. m_reply_ready=0;
  191. }