PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/sources/http_util.cpp

https://github.com/andreisavu/static-httpd
C++ | 377 lines | 230 code | 68 blank | 79 comment | 44 complexity | 50ebac25cbcbe2c338f1e1fb9eba3cb9 MD5 | raw file
  1. // HTTP Server utility classes
  2. /*
  3. Functii utile pentru server
  4. (c) GarajCode 2005-2006 - programmed by Savu Andrei
  5. Date : 27 februarie 2006
  6. Last date : 27 februarie 2006
  7. */
  8. #include "http_util.h"
  9. // Garaj Network Framework
  10. namespace GN
  11. {
  12. // Definire clasa pentru preprocesare cerere HTTP
  13. /// Procesare cerere HTTP
  14. /**
  15. Aceasta functie extrage din cererea HTTP metoda de cerere,
  16. url-ul, versiunea implementarii http si toti parametrii
  17. care urmeaza. r - cererea Http l-lungimea ei
  18. */
  19. void HttpRequest::parse( char * r, int l )
  20. {
  21. char *p = r, *v;
  22. int i=0;
  23. // extrage metoda folosita - mergi pana la primul spatiu.
  24. while( r[i]!=' ' && i<l ) i++;
  25. r[i] = 0;
  26. m_method = p;
  27. i++;
  28. // extrage url - care nu contine spatii
  29. while( r[i]==' ' && i<l ) i++;
  30. p = &r[i];
  31. while( r[i]!=' ' && i<l ) i++;
  32. r[i]=0;
  33. m_url = p;
  34. i++;
  35. // extrage versiune http - pana la primul \n
  36. while( r[i]==' ' && i<l ) i++;
  37. p = &r[i];
  38. while( r[i]!='\n' && i<l ) i++;
  39. r[i]=0;
  40. m_http_version = p;
  41. i++;
  42. // extrage restul parametrilor care
  43. // sunt trimisi sub forma <nume>: <valoare>\n
  44. do
  45. {
  46. if( r[i]=='\n' || r[i+1]=='\n' ) break;
  47. // extrage numele
  48. p = &r[i];
  49. while( r[i]!=':' && r[i]!='\n' && r[i]!=' ' && i<l ) i++;
  50. r[i]=0; i++;
  51. while( r[i]==' ' && i<l ) i++;
  52. // extrage valoarea
  53. v = &r[i];
  54. while( r[i]!='\n' && i<l ) i++;
  55. r[i-1] = 0;
  56. // creaza o variabila cu numele si valoarea gasita
  57. m_ini.set( p, v );
  58. i++;
  59. }while( 1 );
  60. }
  61. /// Converteste un numar din hexa in dec
  62. inline int hex1_to_dec( char a )
  63. {
  64. // daca e cifra
  65. if( a>='0' && a<='9' ) return a-'0';
  66. // daca e litera mica
  67. if( a>='a' && a<='f') return a-'a';
  68. // daca e litera mare
  69. if( a>='A' && a<='F' ) return a-'A';
  70. // eroare - cifra necunoscuta
  71. return -1;
  72. }
  73. /// Converteste un numar hexa
  74. /**
  75. Functie folosita pentru decodarea
  76. url. Converteste un numar hexa de doua
  77. cifre intr-un numar intreg
  78. */
  79. inline int hex2_to_dec( char a, char b )
  80. {
  81. int c1 = hex1_to_dec(a), c2 = hex1_to_dec(b);
  82. if( c1==-1 || c2==-1 )
  83. {
  84. // eroare - a aparut un caracter necunoscut
  85. return -1;
  86. }
  87. return c1*16+c2;
  88. }
  89. /// Decodare URL
  90. /**
  91. Decodare URL - inlocuieste grupurile de trei
  92. litere care incep cu % cu caracterul ASCII
  93. corespunzator.
  94. */
  95. int HttpUrl::decode( char * url )
  96. {
  97. int l = strlen(url), i=0, j=0, aux;
  98. while( i<l )
  99. {
  100. if( url[i]=='%' )
  101. {
  102. // urmatoarele doua caractere sunt un numar
  103. aux = hex2_to_dec( url[i+1], url[i+2] );
  104. if( aux == -1 ) return 0;
  105. // pune caracterul corespunzator
  106. url[j] = (char)aux;
  107. i+=3;
  108. j++;
  109. }
  110. else
  111. {
  112. // copiaza caracterul pur si simplu
  113. url[j] = url[i];
  114. if( url[j]=='/' ) url[j]='\\';
  115. i++;
  116. j++;
  117. }
  118. }
  119. url[j] = 0;
  120. return 1;
  121. }
  122. /// Procesare url
  123. /**
  124. Imparte url-ul in componente logice.
  125. Nume fisier + eventuale variabile trimise prin GET
  126. */
  127. int HttpUrl::parse( const char * http_url, const char * base_folder )
  128. {
  129. // copiaza sirul de caractere din url
  130. char *url, *ext;
  131. if( !(url = new char[ strlen(http_url)+2 ]) ) return 0;
  132. strcpy( url, http_url );
  133. // decodeaza url-ul - caracterele care incep cu %
  134. if( !decode( url ) ) return 0;
  135. // proceseaza url
  136. char *p = url;
  137. int i=0, l=strlen(url);
  138. // extrage numele fisierului, pana la primul ? sau #
  139. // si extensia pentru a putea stabilii content-type
  140. ext = NULL;
  141. while( url[i]!='?' && url[i]!='#' && i<l )
  142. {
  143. if( url[i] == '.' ) ext = &url[i+1];
  144. i++;
  145. }
  146. url[i] = 0;
  147. m_file = base_folder;
  148. m_file += p;
  149. if( ext ) m_ext = ext;
  150. // verifica daca avem sau nu nume de fisier
  151. if( p[strlen(p)-1] == '\\' )
  152. {
  153. m_file += "index.html";
  154. m_ext = "html";
  155. }
  156. i++;
  157. // extrage string-ul pentru query
  158. p = &url[i];
  159. while( url[i]!='#' && i<l ) i++;
  160. url[i] = 0;
  161. m_query = p;
  162. // proceseaza string si extrage valorile
  163. // valorile sunt separate prin = si &
  164. l = strlen(p);
  165. char *r = p;
  166. i = 0;
  167. char *nume, *valoare;
  168. bool has_value;
  169. while( i<l )
  170. {
  171. // extrage numele
  172. nume = &p[i];
  173. has_value = true;
  174. while( p[i]!='=' && p[i]!='&' && i<l ) i++;
  175. if( p[i] == '&' )
  176. {
  177. // avem doar numele
  178. has_value = false;
  179. valoare = NULL;
  180. }
  181. p[i] = 0;
  182. i++;
  183. // extrage valoarea
  184. if( has_value )
  185. {
  186. valoare = &p[i];
  187. while( p[i]!='&' && i<l ) i++;
  188. p[i] = 0;
  189. i++;
  190. }
  191. // adauga o variabila cu acest nume
  192. m_ini.set( nume, valoare );
  193. }
  194. // elibereaza memoria folosita
  195. delete[] url;
  196. return 1;
  197. }
  198. // trimite new line - \n
  199. inline nwl( GN::CSocket& s )
  200. {
  201. try
  202. {
  203. char n = '\n';
  204. s << n;
  205. }
  206. catch(...)
  207. {
  208. throw;
  209. }
  210. }
  211. /// Trimite header de raspuns http
  212. /**
  213. Trimite header de raspuns pentru cererea
  214. http. Header-ul poate contine orice.
  215. */
  216. void HttpResponse::send( GN::CSocket& s )
  217. {
  218. // trimite prima linie si apoi
  219. // fiecare variabila sub forma <nume>: <valoare>\n
  220. // header-ul se incheie cu un \n dublu
  221. if( m_sent ) return;
  222. try
  223. {
  224. s.send( m_txt.c_str(), m_txt.length() ); nwl(s);
  225. // MessageBox( NULL, m_txt.c_str(), "dfg", MB_OK );
  226. for( GSTD::CIni::iterator it=m_ini.begin(); it!=m_ini.end(); it++ )
  227. {
  228. // MessageBox( NULL, (*it).second,(*it).first.c_str() , MB_OK );
  229. if( (*it).second.get_size() )
  230. {
  231. s.send( (*it).first.c_str(), (*it).first.length() );
  232. s.send( ": ", 2 );
  233. s.send( (*it).second, (*it).second.get_size() );
  234. nwl(s);
  235. }
  236. }
  237. nwl(s);
  238. m_sent = true;
  239. }
  240. catch(...)
  241. {
  242. throw;
  243. }
  244. }
  245. /// Set HTTP Response header
  246. void HttpResponse::set_status( int code )
  247. {
  248. switch( code )
  249. {
  250. case HTTP_OK:
  251. set_status( "HTTP/1.0 200 OK" );
  252. break;
  253. case HTTP_CREATED:
  254. set_status( "HTTP/1.0 201 Created" );
  255. break;
  256. case HTTP_ACCEPTED:
  257. set_status( "HTTP/1.0 202 Accepted" );
  258. break;
  259. case HTTP_NO_CONTENT:
  260. set_status( "HTTP/1.0 204 No Content" );
  261. break;
  262. case HTTP_REDIRECT:
  263. set_status( "HTTP/1.0 300 Multiple choice" );
  264. break;
  265. case HTTP_MOVED_PERMANENTLY:
  266. set_status( "HTTP/1.0 301 Moved Permanently" );
  267. break;
  268. case HTTP_MOVED_TEMPORARILY:
  269. set_status( "HTTP/1.0 302 Moved Temporarily" );
  270. break;
  271. case HTTP_NOT_MODIFIED:
  272. set_status( "HTTP/1.0 304 Not Modified" );
  273. break;
  274. case HTTP_BAD_REQUEST:
  275. set_status( "HTTP/1.0 400 Bad request" );
  276. break;
  277. case HTTP_UNAUTHORIZED:
  278. set_status( "HTTP/1.0 401 Unauthorized" );
  279. break;
  280. case HTTP_FORBIDDEN:
  281. set_status( "HTTP/1.0 403 Forbidden" );
  282. break;
  283. case HTTP_NOT_FOUND:
  284. set_status( "HTTP/1.0 404 Not Found" );
  285. break;
  286. case HTTP_SERVER_ERROR:
  287. set_status( "HTTP/1.0 500 Internal Server Error" );
  288. break;
  289. case HTTP_NOT_IMPLEMENTED:
  290. set_status( "HTTP/1.0 501 Not Implemented" );
  291. break;
  292. case HTTP_BAD_GATEWAY:
  293. set_status( "HTTP/1.0 502 Bad Gateway" );
  294. break;
  295. case HTTP_SERVICE_UNAVAIBLE:
  296. set_status( "HTTP/1.0 503 Service Unavaible" );
  297. break;
  298. }
  299. }
  300. /// Seteaza raspuns HTTP pentru redirectare
  301. void HttpResponse::redirect( char * dest )
  302. {
  303. set_status( HTTP_REDIRECT );
  304. set( "Location", dest );
  305. }
  306. }; // GN