shttpd.c 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903
  1. /*
  2. * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
  3. * All rights reserved
  4. *
  5. * "THE BEER-WARE LICENSE" (Revision 42):
  6. * Sergey Lyubka wrote this file. As long as you retain this notice you
  7. * can do whatever you want with this stuff. If we meet some day, and you think
  8. * this stuff is worth it, you can buy me a beer in return.
  9. */
  10. /*
  11. * Small and portable HTTP server, http://shttpd.sourceforge.net
  12. * $Id: shttpd.c,v 1.57 2008/08/23 21:00:38 drozd Exp $
  13. */
  14. #include "defs.h"
  15. time_t _shttpd_current_time; /* Current UTC time */
  16. int _shttpd_tz_offset; /* Time zone offset from UTC */
  17. int _shttpd_exit_flag; /* Program exit flag */
  18. const struct vec _shttpd_known_http_methods[] = {
  19. {"GET", 3},
  20. {"POST", 4},
  21. {"PUT", 3},
  22. {"DELETE", 6},
  23. {"HEAD", 4},
  24. {NULL, 0}
  25. };
  26. /*
  27. * This structure tells how HTTP headers must be parsed.
  28. * Used by parse_headers() function.
  29. */
  30. #define OFFSET(x) offsetof(struct headers, x)
  31. static const struct http_header http_headers[] = {
  32. {16, HDR_INT, OFFSET(cl), "Content-Length: " },
  33. {14, HDR_STRING, OFFSET(ct), "Content-Type: " },
  34. {12, HDR_STRING, OFFSET(useragent), "User-Agent: " },
  35. {19, HDR_DATE, OFFSET(ims), "If-Modified-Since: " },
  36. {15, HDR_STRING, OFFSET(auth), "Authorization: " },
  37. {9, HDR_STRING, OFFSET(referer), "Referer: " },
  38. {8, HDR_STRING, OFFSET(cookie), "Cookie: " },
  39. {10, HDR_STRING, OFFSET(location), "Location: " },
  40. {8, HDR_INT, OFFSET(status), "Status: " },
  41. {7, HDR_STRING, OFFSET(range), "Range: " },
  42. {12, HDR_STRING, OFFSET(connection), "Connection: " },
  43. {19, HDR_STRING, OFFSET(transenc), "Transfer-Encoding: " },
  44. {0, HDR_INT, 0, NULL }
  45. };
  46. struct shttpd_ctx *init_ctx(const char *config_file, int argc, char *argv[]);
  47. static void process_connection(struct conn *, int, int);
  48. int
  49. _shttpd_is_true(const char *str)
  50. {
  51. static const char *trues[] = {"1", "yes", "true", "jawohl", NULL};
  52. const char **p;
  53. for (p = trues; *p != NULL; p++)
  54. if (str && !strcmp(str, *p))
  55. return (TRUE);
  56. return (FALSE);
  57. }
  58. static void
  59. free_list(struct llhead *head, void (*dtor)(struct llhead *))
  60. {
  61. struct llhead *lp, *tmp;
  62. LL_FOREACH_SAFE(head, lp, tmp) {
  63. LL_DEL(lp);
  64. dtor(lp);
  65. }
  66. }
  67. static void
  68. listener_destructor(struct llhead *lp)
  69. {
  70. struct listener *listener = LL_ENTRY(lp, struct listener, link);
  71. (void) closesocket(listener->sock);
  72. free(listener);
  73. }
  74. static void
  75. registered_uri_destructor(struct llhead *lp)
  76. {
  77. struct registered_uri *ruri = LL_ENTRY(lp, struct registered_uri, link);
  78. free((void *) ruri->uri);
  79. free(ruri);
  80. }
  81. static void
  82. acl_destructor(struct llhead *lp)
  83. {
  84. struct acl *acl = LL_ENTRY(lp, struct acl, link);
  85. free(acl);
  86. }
  87. int
  88. _shttpd_url_decode(const char *src, int src_len, char *dst, int dst_len)
  89. {
  90. int i, j, a, b;
  91. #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
  92. for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++)
  93. switch (src[i]) {
  94. case '%':
  95. if (isxdigit(((unsigned char *) src)[i + 1]) &&
  96. isxdigit(((unsigned char *) src)[i + 2])) {
  97. a = tolower(((unsigned char *)src)[i + 1]);
  98. b = tolower(((unsigned char *)src)[i + 2]);
  99. dst[j] = (HEXTOI(a) << 4) | HEXTOI(b);
  100. i += 2;
  101. } else {
  102. dst[j] = '%';
  103. }
  104. break;
  105. default:
  106. dst[j] = src[i];
  107. break;
  108. }
  109. dst[j] = '\0'; /* Null-terminate the destination */
  110. return (j);
  111. }
  112. static const char *
  113. is_alias(struct shttpd_ctx *ctx, const char *uri,
  114. struct vec *a_uri, struct vec *a_path)
  115. {
  116. const char *p, *s = ctx->options[OPT_ALIASES];
  117. size_t len;
  118. DBG(("is_alias: aliases [%s]", s == NULL ? "" : s));
  119. FOR_EACH_WORD_IN_LIST(s, len) {
  120. if ((p = memchr(s, '=', len)) == NULL || p >= s + len || p == s)
  121. continue;
  122. if (memcmp(uri, s, p - s) == 0) {
  123. a_uri->ptr = s;
  124. a_uri->len = p - s;
  125. a_path->ptr = ++p;
  126. a_path->len = (s + len) - p;
  127. return (s);
  128. }
  129. }
  130. return (NULL);
  131. }
  132. void
  133. _shttpd_stop_stream(struct stream *stream)
  134. {
  135. if (stream->io_class != NULL && stream->io_class->close != NULL)
  136. stream->io_class->close(stream);
  137. stream->io_class= NULL;
  138. stream->flags |= FLAG_CLOSED;
  139. stream->flags &= ~(FLAG_R | FLAG_W | FLAG_ALWAYS_READY);
  140. DBG(("%d %s stopped. %lu of content data, %d now in a buffer",
  141. stream->conn->rem.chan.sock,
  142. stream->io_class ? stream->io_class->name : "(null)",
  143. (unsigned long) stream->io.total, (int) io_data_len(&stream->io)));
  144. }
  145. /*
  146. * Setup listening socket on given port, return socket
  147. */
  148. static int
  149. shttpd_open_listening_port(int port)
  150. {
  151. int sock, on = 1;
  152. struct usa sa;
  153. #ifdef _WIN32
  154. {WSADATA data; WSAStartup(MAKEWORD(2,2), &data);}
  155. #endif /* _WIN32 */
  156. sa.len = sizeof(sa.u.sin);
  157. sa.u.sin.sin_family = AF_INET;
  158. sa.u.sin.sin_port = htons((uint16_t) port);
  159. sa.u.sin.sin_addr.s_addr = htonl(INADDR_ANY);
  160. if ((sock = socket(PF_INET, SOCK_STREAM, 6)) == -1)
  161. goto fail;
  162. if (_shttpd_set_non_blocking_mode(sock) != 0)
  163. goto fail;
  164. if (setsockopt(sock, SOL_SOCKET,
  165. SO_REUSEADDR,(char *) &on, sizeof(on)) != 0)
  166. goto fail;
  167. if (bind(sock, &sa.u.sa, sa.len) < 0)
  168. goto fail;
  169. if (listen(sock, 128) != 0)
  170. goto fail;
  171. #ifndef _WIN32
  172. (void) fcntl(sock, F_SETFD, FD_CLOEXEC);
  173. #endif /* !_WIN32 */
  174. return (sock);
  175. fail:
  176. if (sock != -1)
  177. (void) closesocket(sock);
  178. _shttpd_elog(E_LOG, NULL, "open_listening_port(%d): %s", port, strerror(errno));
  179. return (-1);
  180. }
  181. /*
  182. * Check whether full request is buffered Return headers length, or 0
  183. */
  184. int
  185. _shttpd_get_headers_len(const char *buf, size_t buflen)
  186. {
  187. const char *s, *e;
  188. int len = 0;
  189. for (s = buf, e = s + buflen - 1; len == 0 && s < e; s++)
  190. /* Control characters are not allowed but >=128 is. */
  191. if (!isprint(* (unsigned char *) s) && *s != '\r' &&
  192. *s != '\n' && * (unsigned char *) s < 128)
  193. len = -1;
  194. else if (s[0] == '\n' && s[1] == '\n')
  195. len = s - buf + 2;
  196. else if (s[0] == '\n' && &s[1] < e &&
  197. s[1] == '\r' && s[2] == '\n')
  198. len = s - buf + 3;
  199. return (len);
  200. }
  201. /*
  202. * Send error message back to a client.
  203. */
  204. void
  205. _shttpd_send_server_error(struct conn *c, int status, const char *reason)
  206. {
  207. struct llhead *lp;
  208. struct error_handler *e;
  209. LL_FOREACH(&c->ctx->error_handlers, lp) {
  210. e = LL_ENTRY(lp, struct error_handler, link);
  211. if (e->code == status) {
  212. if (c->loc.io_class != NULL &&
  213. c->loc.io_class->close != NULL)
  214. c->loc.io_class->close(&c->loc);
  215. io_clear(&c->loc.io);
  216. _shttpd_setup_embedded_stream(c,
  217. e->callback, e->callback_data);
  218. return;
  219. }
  220. }
  221. io_clear(&c->loc.io);
  222. c->loc.io.head = _shttpd_snprintf(c->loc.io.buf, c->loc.io.size,
  223. "HTTP/1.1 %d %s\r\n"
  224. "Content-Type: text/plain\r\n"
  225. "Content-Length: 12\r\n"
  226. "\r\n"
  227. "Error: %03d\r\n",
  228. status, reason, status);
  229. c->loc.content_len = 10;
  230. c->status = status;
  231. _shttpd_stop_stream(&c->loc);
  232. }
  233. /*
  234. * Convert month to the month number. Return -1 on error, or month number
  235. */
  236. static int
  237. montoi(const char *s)
  238. {
  239. static const char *ar[] = {
  240. "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  241. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  242. };
  243. size_t i;
  244. for (i = 0; i < sizeof(ar) / sizeof(ar[0]); i++)
  245. if (!strcmp(s, ar[i]))
  246. return (i);
  247. return (-1);
  248. }
  249. /*
  250. * Parse date-time string, and return the corresponding time_t value
  251. */
  252. static time_t
  253. date_to_epoch(const char *s)
  254. {
  255. struct tm tm, *tmp;
  256. char mon[32];
  257. int sec, min, hour, mday, month, year;
  258. (void) memset(&tm, 0, sizeof(tm));
  259. sec = min = hour = mday = month = year = 0;
  260. if (((sscanf(s, "%d/%3s/%d %d:%d:%d",
  261. &mday, mon, &year, &hour, &min, &sec) == 6) ||
  262. (sscanf(s, "%d %3s %d %d:%d:%d",
  263. &mday, mon, &year, &hour, &min, &sec) == 6) ||
  264. (sscanf(s, "%*3s, %d %3s %d %d:%d:%d",
  265. &mday, mon, &year, &hour, &min, &sec) == 6) ||
  266. (sscanf(s, "%d-%3s-%d %d:%d:%d",
  267. &mday, mon, &year, &hour, &min, &sec) == 6)) &&
  268. (month = montoi(mon)) != -1) {
  269. tm.tm_mday = mday;
  270. tm.tm_mon = month;
  271. tm.tm_year = year;
  272. tm.tm_hour = hour;
  273. tm.tm_min = min;
  274. tm.tm_sec = sec;
  275. }
  276. if (tm.tm_year > 1900)
  277. tm.tm_year -= 1900;
  278. else if (tm.tm_year < 70)
  279. tm.tm_year += 100;
  280. /* Set Daylight Saving Time field */
  281. tmp = localtime(&_shttpd_current_time);
  282. tm.tm_isdst = tmp->tm_isdst;
  283. return (mktime(&tm));
  284. }
  285. static void
  286. remove_double_dots(char *s)
  287. {
  288. char *p = s;
  289. while (*s != '\0') {
  290. *p++ = *s++;
  291. if (s[-1] == '/' || s[-1] == '\\')
  292. while (*s == '.' || *s == '/' || *s == '\\')
  293. s++;
  294. }
  295. *p = '\0';
  296. }
  297. void
  298. _shttpd_parse_headers(const char *s, int len, struct headers *parsed)
  299. {
  300. const struct http_header *h;
  301. union variant *v;
  302. const char *p, *e = s + len;
  303. DBG(("parsing headers (len %d): [%.*s]", len, len, s));
  304. /* Loop through all headers in the request */
  305. while (s < e) {
  306. /* Find where this header ends */
  307. for (p = s; p < e && *p != '\n'; ) p++;
  308. /* Is this header known to us ? */
  309. for (h = http_headers; h->len != 0; h++)
  310. if (e - s > h->len &&
  311. !_shttpd_strncasecmp(s, h->name, h->len))
  312. break;
  313. /* If the header is known to us, store its value */
  314. if (h->len != 0) {
  315. /* Shift to where value starts */
  316. s += h->len;
  317. /* Find place to store the value */
  318. v = (union variant *) ((char *) parsed + h->offset);
  319. /* Fetch header value into the connection structure */
  320. if (h->type == HDR_STRING) {
  321. v->v_vec.ptr = s;
  322. v->v_vec.len = p - s;
  323. if (p[-1] == '\r' && v->v_vec.len > 0)
  324. v->v_vec.len--;
  325. } else if (h->type == HDR_INT) {
  326. v->v_big_int = strtoul(s, NULL, 10);
  327. } else if (h->type == HDR_DATE) {
  328. v->v_time = date_to_epoch(s);
  329. }
  330. }
  331. s = p + 1; /* Shift to the next header */
  332. }
  333. }
  334. static const struct {
  335. const char *extension;
  336. int ext_len;
  337. const char *mime_type;
  338. } builtin_mime_types[] = {
  339. {"html", 4, "text/html" },
  340. {"htm", 3, "text/html" },
  341. {"txt", 3, "text/plain" },
  342. {"css", 3, "text/css" },
  343. {"ico", 3, "image/x-icon" },
  344. {"gif", 3, "image/gif" },
  345. {"jpg", 3, "image/jpeg" },
  346. {"jpeg", 4, "image/jpeg" },
  347. {"png", 3, "image/png" },
  348. {"svg", 3, "image/svg+xml" },
  349. {"torrent", 7, "application/x-bittorrent" },
  350. {"wav", 3, "audio/x-wav" },
  351. {"mp3", 3, "audio/x-mp3" },
  352. {"mid", 3, "audio/mid" },
  353. {"m3u", 3, "audio/x-mpegurl" },
  354. {"ram", 3, "audio/x-pn-realaudio" },
  355. {"ra", 2, "audio/x-pn-realaudio" },
  356. {"doc", 3, "application/msword", },
  357. {"exe", 3, "application/octet-stream" },
  358. {"zip", 3, "application/x-zip-compressed" },
  359. {"xls", 3, "application/excel" },
  360. {"tgz", 3, "application/x-tar-gz" },
  361. {"tar.gz", 6, "application/x-tar-gz" },
  362. {"tar", 3, "application/x-tar" },
  363. {"gz", 2, "application/x-gunzip" },
  364. {"arj", 3, "application/x-arj-compressed" },
  365. {"rar", 3, "application/x-arj-compressed" },
  366. {"rtf", 3, "application/rtf" },
  367. {"pdf", 3, "application/pdf" },
  368. {"swf", 3, "application/x-shockwave-flash" },
  369. {"mpg", 3, "video/mpeg" },
  370. {"mpeg", 4, "video/mpeg" },
  371. {"asf", 3, "video/x-ms-asf" },
  372. {"avi", 3, "video/x-msvideo" },
  373. {"bmp", 3, "image/bmp" },
  374. {NULL, 0, NULL }
  375. };
  376. void
  377. _shttpd_get_mime_type(struct shttpd_ctx *ctx,
  378. const char *uri, int len, struct vec *vec)
  379. {
  380. const char *eq, *p = ctx->options[OPT_MIME_TYPES];
  381. int i, n, ext_len;
  382. /* Firt, loop through the custom mime types if any */
  383. FOR_EACH_WORD_IN_LIST(p, n) {
  384. if ((eq = memchr(p, '=', n)) == NULL || eq >= p + n || eq == p)
  385. continue;
  386. ext_len = eq - p;
  387. if (len > ext_len && uri[len - ext_len - 1] == '.' &&
  388. !_shttpd_strncasecmp(p, &uri[len - ext_len], ext_len)) {
  389. vec->ptr = eq + 1;
  390. vec->len = p + n - vec->ptr;
  391. return;
  392. }
  393. }
  394. /* If no luck, try built-in mime types */
  395. for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
  396. ext_len = builtin_mime_types[i].ext_len;
  397. if (len > ext_len && uri[len - ext_len - 1] == '.' &&
  398. !_shttpd_strncasecmp(builtin_mime_types[i].extension,
  399. &uri[len - ext_len], ext_len)) {
  400. vec->ptr = builtin_mime_types[i].mime_type;
  401. vec->len = strlen(vec->ptr);
  402. return;
  403. }
  404. }
  405. /* Oops. This extension is unknown to us. Fallback to text/plain */
  406. vec->ptr = "text/plain";
  407. vec->len = strlen(vec->ptr);
  408. }
  409. /*
  410. * For given directory path, substitute it to valid index file.
  411. * Return 0 if index file has been found, -1 if not found
  412. */
  413. static int
  414. find_index_file(struct conn *c, char *path, size_t maxpath, struct stat *stp)
  415. {
  416. char buf[FILENAME_MAX];
  417. const char *s = c->ctx->options[OPT_INDEX_FILES];
  418. size_t len;
  419. FOR_EACH_WORD_IN_LIST(s, len) {
  420. /* path must end with '/' character */
  421. _shttpd_snprintf(buf, sizeof(buf), "%s%.*s", path, len, s);
  422. if (_shttpd_stat(buf, stp) == 0) {
  423. _shttpd_strlcpy(path, buf, maxpath);
  424. _shttpd_get_mime_type(c->ctx, s, len, &c->mime_type);
  425. return (0);
  426. }
  427. }
  428. return (-1);
  429. }
  430. /*
  431. * Try to open requested file, return 0 if OK, -1 if error.
  432. * If the file is given arguments using PATH_INFO mechanism,
  433. * initialize pathinfo pointer.
  434. */
  435. static int
  436. get_path_info(struct conn *c, char *path, struct stat *stp)
  437. {
  438. char *p, *e;
  439. if (_shttpd_stat(path, stp) == 0)
  440. return (0);
  441. p = path + strlen(path);
  442. e = path + strlen(c->ctx->options[OPT_ROOT]) + 2;
  443. /* Strip directory parts of the path one by one */
  444. for (; p > e; p--)
  445. if (*p == '/') {
  446. *p = '\0';
  447. if (!_shttpd_stat(path, stp) && !S_ISDIR(stp->st_mode)) {
  448. c->path_info = p + 1;
  449. return (0);
  450. } else {
  451. *p = '/';
  452. }
  453. }
  454. return (-1);
  455. }
  456. static void
  457. decide_what_to_do(struct conn *c)
  458. {
  459. char path[URI_MAX], buf[1024], *root;
  460. struct vec alias_uri, alias_path;
  461. struct stat st;
  462. int rc;
  463. struct registered_uri *ruri;
  464. DBG(("decide_what_to_do: [%s]", c->uri));
  465. if ((c->query = strchr(c->uri, '?')) != NULL)
  466. *c->query++ = '\0';
  467. _shttpd_url_decode(c->uri, strlen(c->uri), c->uri, strlen(c->uri) + 1);
  468. remove_double_dots(c->uri);
  469. root = c->ctx->options[OPT_ROOT];
  470. if (strlen(c->uri) + strlen(root) >= sizeof(path)) {
  471. _shttpd_send_server_error(c, 400, "URI is too long");
  472. return;
  473. }
  474. (void) _shttpd_snprintf(path, sizeof(path), "%s%s", root, c->uri);
  475. /* User may use the aliases - check URI for mount point */
  476. if (is_alias(c->ctx, c->uri, &alias_uri, &alias_path) != NULL) {
  477. (void) _shttpd_snprintf(path, sizeof(path), "%.*s%s",
  478. alias_path.len, alias_path.ptr, c->uri + alias_uri.len);
  479. DBG(("using alias %.*s -> %.*s", alias_uri.len, alias_uri.ptr,
  480. alias_path.len, alias_path.ptr));
  481. }
  482. #if !defined(NO_AUTH)
  483. if (_shttpd_check_authorization(c, path) != 1) {
  484. _shttpd_send_authorization_request(c);
  485. } else
  486. #endif /* NO_AUTH */
  487. if ((ruri = _shttpd_is_registered_uri(c->ctx, c->uri)) != NULL) {
  488. _shttpd_setup_embedded_stream(c,
  489. ruri->callback, ruri->callback_data);
  490. } else
  491. if (strstr(path, HTPASSWD)) {
  492. /* Do not allow to view passwords files */
  493. _shttpd_send_server_error(c, 403, "Forbidden");
  494. } else
  495. #if !defined(NO_AUTH)
  496. if ((c->method == METHOD_PUT || c->method == METHOD_DELETE) &&
  497. (c->ctx->options[OPT_AUTH_PUT] == NULL ||
  498. !_shttpd_is_authorized_for_put(c))) {
  499. _shttpd_send_authorization_request(c);
  500. } else
  501. #endif /* NO_AUTH */
  502. if (c->method == METHOD_PUT) {
  503. c->status = _shttpd_stat(path, &st) == 0 ? 200 : 201;
  504. if (c->ch.range.v_vec.len > 0) {
  505. _shttpd_send_server_error(c, 501,
  506. "PUT Range Not Implemented");
  507. } else if ((rc = _shttpd_put_dir(path)) == 0) {
  508. _shttpd_send_server_error(c, 200, "OK");
  509. } else if (rc == -1) {
  510. _shttpd_send_server_error(c, 500, "PUT Directory Error");
  511. } else if (c->rem.content_len == 0) {
  512. _shttpd_send_server_error(c, 411, "Length Required");
  513. } else if ((c->loc.chan.fd = _shttpd_open(path, O_WRONLY | O_BINARY |
  514. O_CREAT | O_NONBLOCK | O_TRUNC, 0644)) == -1) {
  515. _shttpd_send_server_error(c, 500, "PUT Error");
  516. } else {
  517. DBG(("PUT file [%s]", c->uri));
  518. c->loc.io_class = &_shttpd_io_file;
  519. c->loc.flags |= FLAG_W | FLAG_ALWAYS_READY ;
  520. }
  521. } else if (c->method == METHOD_DELETE) {
  522. DBG(("DELETE [%s]", c->uri));
  523. if (_shttpd_remove(path) == 0)
  524. _shttpd_send_server_error(c, 200, "OK");
  525. else
  526. _shttpd_send_server_error(c, 500, "DELETE Error");
  527. } else if (get_path_info(c, path, &st) != 0) {
  528. _shttpd_send_server_error(c, 404, "Not Found");
  529. } else if (S_ISDIR(st.st_mode) && path[strlen(path) - 1] != '/') {
  530. (void) _shttpd_snprintf(buf, sizeof(buf),
  531. "Moved Permanently\r\nLocation: %s/", c->uri);
  532. _shttpd_send_server_error(c, 301, buf);
  533. } else if (S_ISDIR(st.st_mode) &&
  534. find_index_file(c, path, sizeof(path) - 1, &st) == -1 &&
  535. !IS_TRUE(c->ctx, OPT_DIR_LIST)) {
  536. _shttpd_send_server_error(c, 403, "Directory Listing Denied");
  537. } else if (S_ISDIR(st.st_mode) && IS_TRUE(c->ctx, OPT_DIR_LIST)) {
  538. if ((c->loc.chan.dir.path = _shttpd_strdup(path)) != NULL)
  539. _shttpd_get_dir(c);
  540. else
  541. _shttpd_send_server_error(c, 500, "GET Directory Error");
  542. } else if (S_ISDIR(st.st_mode) && !IS_TRUE(c->ctx, OPT_DIR_LIST)) {
  543. _shttpd_send_server_error(c, 403, "Directory listing denied");
  544. #if !defined(NO_CGI)
  545. } else if (_shttpd_match_extension(path,
  546. c->ctx->options[OPT_CGI_EXTENSIONS])) {
  547. if (c->method != METHOD_POST && c->method != METHOD_GET) {
  548. _shttpd_send_server_error(c, 501, "Bad method ");
  549. } else if ((_shttpd_run_cgi(c, path)) == -1) {
  550. _shttpd_send_server_error(c, 500, "Cannot exec CGI");
  551. } else {
  552. _shttpd_do_cgi(c);
  553. }
  554. #endif /* NO_CGI */
  555. #if !defined(NO_SSI)
  556. } else if (_shttpd_match_extension(path,
  557. c->ctx->options[OPT_SSI_EXTENSIONS])) {
  558. if ((c->loc.chan.fd = _shttpd_open(path,
  559. O_RDONLY | O_BINARY, 0644)) == -1) {
  560. _shttpd_send_server_error(c, 500, "SSI open error");
  561. } else {
  562. _shttpd_do_ssi(c);
  563. }
  564. #endif /* NO_CGI */
  565. } else if (c->ch.ims.v_time && st.st_mtime <= c->ch.ims.v_time) {
  566. _shttpd_send_server_error(c, 304, "Not Modified");
  567. } else if ((c->loc.chan.fd = _shttpd_open(path,
  568. O_RDONLY | O_BINARY, 0644)) != -1) {
  569. _shttpd_get_file(c, &st);
  570. } else {
  571. _shttpd_send_server_error(c, 500, "Internal Error");
  572. }
  573. }
  574. static int
  575. set_request_method(struct conn *c)
  576. {
  577. const struct vec *v;
  578. /* Set the request method */
  579. for (v = _shttpd_known_http_methods; v->ptr != NULL; v++)
  580. if (!memcmp(c->rem.io.buf, v->ptr, v->len)) {
  581. c->method = v - _shttpd_known_http_methods;
  582. break;
  583. }
  584. return (v->ptr == NULL);
  585. }
  586. static void
  587. parse_http_request(struct conn *c)
  588. {
  589. char *s, *e, *p, *start;
  590. int uri_len, req_len, n;
  591. s = io_data(&c->rem.io);;
  592. req_len = c->rem.headers_len =
  593. _shttpd_get_headers_len(s, io_data_len(&c->rem.io));
  594. if (req_len == 0 && io_space_len(&c->rem.io) == 0) {
  595. io_clear(&c->rem.io);
  596. _shttpd_send_server_error(c, 400, "Request is too big");
  597. }
  598. if (req_len == 0) {
  599. return;
  600. } else if (req_len < 16) { /* Minimal: "GET / HTTP/1.0\n\n" */
  601. _shttpd_send_server_error(c, 400, "Bad request");
  602. } else if (set_request_method(c)) {
  603. _shttpd_send_server_error(c, 501, "Method Not Implemented");
  604. } else if ((c->request = _shttpd_strndup(s, req_len)) == NULL) {
  605. _shttpd_send_server_error(c, 500, "Cannot allocate request");
  606. }
  607. if (c->loc.flags & FLAG_CLOSED)
  608. return;
  609. io_inc_tail(&c->rem.io, req_len);
  610. DBG(("Conn %d: parsing request: [%.*s]", c->rem.chan.sock, req_len, s));
  611. c->rem.flags |= FLAG_HEADERS_PARSED;
  612. /* Set headers pointer. Headers follow the request line */
  613. c->headers = memchr(c->request, '\n', req_len);
  614. assert(c->headers != NULL);
  615. assert(c->headers < c->request + req_len);
  616. if (c->headers > c->request && c->headers[-1] == '\r')
  617. c->headers[-1] = '\0';
  618. *c->headers++ = '\0';
  619. /*
  620. * Now make a copy of the URI, because it will be URL-decoded,
  621. * and we need a copy of unmodified URI for the access log.
  622. * First, we skip the REQUEST_METHOD and shift to the URI.
  623. */
  624. for (p = c->request, e = p + req_len; *p != ' ' && p < e; p++);
  625. while (p < e && *p == ' ')
  626. p++;
  627. /* Now remember where URI starts, and shift to the end of URI */
  628. for (start = p; p < e && !isspace((unsigned char)*p); ) p++;
  629. uri_len = p - start;
  630. /* Skip space following the URI */
  631. while (p < e && *p == ' ')
  632. p++;
  633. /* Now comes the HTTP-Version in the form HTTP/<major>.<minor> */
  634. if (sscanf(p, "HTTP/%lu.%lu%n",
  635. &c->major_version, &c->minor_version, &n) != 2 || p[n] != '\0') {
  636. _shttpd_send_server_error(c, 400, "Bad HTTP version");
  637. } else if (c->major_version > 1 ||
  638. (c->major_version == 1 && c->minor_version > 1)) {
  639. _shttpd_send_server_error(c, 505, "HTTP version not supported");
  640. } else if (uri_len <= 0) {
  641. _shttpd_send_server_error(c, 400, "Bad URI");
  642. } else if ((c->uri = malloc(uri_len + 1)) == NULL) {
  643. _shttpd_send_server_error(c, 500, "Cannot allocate URI");
  644. } else {
  645. _shttpd_strlcpy(c->uri, (char *) start, uri_len + 1);
  646. _shttpd_parse_headers(c->headers,
  647. (c->request + req_len) - c->headers, &c->ch);
  648. /* Remove the length of request from total, count only data */
  649. assert(c->rem.io.total >= (big_int_t) req_len);
  650. c->rem.io.total -= req_len;
  651. c->rem.content_len = c->ch.cl.v_big_int;
  652. decide_what_to_do(c);
  653. }
  654. }
  655. static void
  656. add_socket(struct worker *worker, int sock, int is_ssl)
  657. {
  658. struct shttpd_ctx *ctx = worker->ctx;
  659. struct conn *c;
  660. struct usa sa;
  661. int l = IS_TRUE(ctx, OPT_INETD) ? E_FATAL : E_LOG;
  662. #if !defined(NO_SSL)
  663. SSL *ssl = NULL;
  664. #else
  665. is_ssl = is_ssl; /* supress warnings */
  666. #endif /* NO_SSL */
  667. sa.len = sizeof(sa.u.sin);
  668. (void) _shttpd_set_non_blocking_mode(sock);
  669. if (getpeername(sock, &sa.u.sa, &sa.len)) {
  670. _shttpd_elog(l, NULL, "add_socket: %s", strerror(errno));
  671. #if !defined(NO_SSL)
  672. } else if (is_ssl && (ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
  673. _shttpd_elog(l, NULL, "add_socket: SSL_new: %s", strerror(ERRNO));
  674. (void) closesocket(sock);
  675. } else if (is_ssl && SSL_set_fd(ssl, sock) == 0) {
  676. _shttpd_elog(l, NULL, "add_socket: SSL_set_fd: %s", strerror(ERRNO));
  677. (void) closesocket(sock);
  678. SSL_free(ssl);
  679. #endif /* NO_SSL */
  680. } else if ((c = calloc(1, sizeof(*c) + 2 * URI_MAX)) == NULL) {
  681. #if !defined(NO_SSL)
  682. if (ssl)
  683. SSL_free(ssl);
  684. #endif /* NO_SSL */
  685. (void) closesocket(sock);
  686. _shttpd_elog(l, NULL, "add_socket: calloc: %s", strerror(ERRNO));
  687. } else {
  688. c->rem.conn = c->loc.conn = c;
  689. c->ctx = ctx;
  690. c->worker = worker;
  691. c->sa = sa;
  692. c->birth_time = _shttpd_current_time;
  693. c->expire_time = _shttpd_current_time + EXPIRE_TIME;
  694. (void) getsockname(sock, &sa.u.sa, &sa.len);
  695. c->loc_port = sa.u.sin.sin_port;
  696. _shttpd_set_close_on_exec(sock);
  697. c->loc.io_class = NULL;
  698. c->rem.io_class = &_shttpd_io_socket;
  699. c->rem.chan.sock = sock;
  700. /* Set IO buffers */
  701. c->loc.io.buf = (char *) (c + 1);
  702. c->rem.io.buf = c->loc.io.buf + URI_MAX;
  703. c->loc.io.size = c->rem.io.size = URI_MAX;
  704. #if !defined(NO_SSL)
  705. if (is_ssl) {
  706. c->rem.io_class = &_shttpd_io_ssl;
  707. c->rem.chan.ssl.sock = sock;
  708. c->rem.chan.ssl.ssl = ssl;
  709. _shttpd_ssl_handshake(&c->rem);
  710. }
  711. #endif /* NO_SSL */
  712. LL_TAIL(&worker->connections, &c->link);
  713. worker->num_conns++;
  714. DBG(("%s:%hu connected (socket %d)",
  715. inet_ntoa(* (struct in_addr *) &sa.u.sin.sin_addr.s_addr),
  716. ntohs(sa.u.sin.sin_port), sock));
  717. }
  718. }
  719. static struct worker *
  720. first_worker(struct shttpd_ctx *ctx)
  721. {
  722. return (LL_ENTRY(ctx->workers.next, struct worker, link));
  723. }
  724. static void
  725. pass_socket(struct shttpd_ctx *ctx, int sock, int is_ssl)
  726. {
  727. struct llhead *lp;
  728. struct worker *worker, *lazy;
  729. int buf[3];
  730. lazy = first_worker(ctx);
  731. /* Find least busy worker */
  732. LL_FOREACH(&ctx->workers, lp) {
  733. worker = LL_ENTRY(lp, struct worker, link);
  734. if (worker->num_conns < lazy->num_conns)
  735. lazy = worker;
  736. }
  737. buf[0] = CTL_PASS_SOCKET;
  738. buf[1] = sock;
  739. buf[2] = is_ssl;
  740. (void) send(lazy->ctl[1], (void *) buf, sizeof(buf), 0);
  741. }
  742. static int
  743. set_ports(struct shttpd_ctx *ctx, const char *p)
  744. {
  745. int sock, len, is_ssl, port;
  746. struct listener *l;
  747. free_list(&ctx->listeners, &listener_destructor);
  748. FOR_EACH_WORD_IN_LIST(p, len) {
  749. is_ssl = p[len - 1] == 's' ? 1 : 0;
  750. port = atoi(p);
  751. if ((sock = shttpd_open_listening_port(port)) == -1) {
  752. _shttpd_elog(E_LOG, NULL, "cannot open port %d", port);
  753. goto fail;
  754. } else if (is_ssl && ctx->ssl_ctx == NULL) {
  755. (void) closesocket(sock);
  756. _shttpd_elog(E_LOG, NULL, "cannot add SSL socket, "
  757. "please specify certificate file");
  758. goto fail;
  759. } else if ((l = calloc(1, sizeof(*l))) == NULL) {
  760. (void) closesocket(sock);
  761. _shttpd_elog(E_LOG, NULL, "cannot allocate listener");
  762. goto fail;
  763. } else {
  764. l->is_ssl = is_ssl;
  765. l->sock = sock;
  766. l->ctx = ctx;
  767. LL_TAIL(&ctx->listeners, &l->link);
  768. DBG(("shttpd_listen: added socket %d", sock));
  769. }
  770. }
  771. return (TRUE);
  772. fail:
  773. free_list(&ctx->listeners, &listener_destructor);
  774. return (FALSE);
  775. }
  776. static void
  777. read_stream(struct stream *stream)
  778. {
  779. int n, len;
  780. len = io_space_len(&stream->io);
  781. assert(len > 0);
  782. /* Do not read more that needed */
  783. if (stream->content_len > 0 &&
  784. stream->io.total + len > stream->content_len)
  785. len = stream->content_len - stream->io.total;
  786. /* Read from underlying channel */
  787. assert(stream->io_class != NULL);
  788. n = stream->io_class->read(stream, io_space(&stream->io), len);
  789. if (n > 0)
  790. io_inc_head(&stream->io, n);
  791. else if (n == -1 && (ERRNO == EINTR || ERRNO == EWOULDBLOCK))
  792. n = n; /* Ignore EINTR and EAGAIN */
  793. else if (!(stream->flags & FLAG_DONT_CLOSE))
  794. _shttpd_stop_stream(stream);
  795. DBG(("read_stream (%d %s): read %d/%d/%lu bytes (errno %d)",
  796. stream->conn->rem.chan.sock,
  797. stream->io_class ? stream->io_class->name : "(null)",
  798. n, len, (unsigned long) stream->io.total, ERRNO));
  799. /*
  800. * Close the local stream if everything was read
  801. * XXX We do not close the remote stream though! It may be
  802. * a POST data completed transfer, we do not want the socket
  803. * to be closed.
  804. */
  805. if (stream->content_len > 0 && stream == &stream->conn->loc) {
  806. assert(stream->io.total <= stream->content_len);
  807. if (stream->io.total == stream->content_len)
  808. _shttpd_stop_stream(stream);
  809. }
  810. stream->conn->expire_time = _shttpd_current_time + EXPIRE_TIME;
  811. }
  812. static void
  813. write_stream(struct stream *from, struct stream *to)
  814. {
  815. int n, len;
  816. len = io_data_len(&from->io);
  817. assert(len > 0);
  818. /* TODO: should be assert on CAN_WRITE flag */
  819. n = to->io_class->write(to, io_data(&from->io), len);
  820. to->conn->expire_time = _shttpd_current_time + EXPIRE_TIME;
  821. DBG(("write_stream (%d %s): written %d/%d bytes (errno %d)",
  822. to->conn->rem.chan.sock,
  823. to->io_class ? to->io_class->name : "(null)", n, len, ERRNO));
  824. if (n > 0)
  825. io_inc_tail(&from->io, n);
  826. else if (n == -1 && (ERRNO == EINTR || ERRNO == EWOULDBLOCK))
  827. n = n; /* Ignore EINTR and EAGAIN */
  828. else if (!(to->flags & FLAG_DONT_CLOSE))
  829. _shttpd_stop_stream(to);
  830. }
  831. static void
  832. connection_desctructor(struct llhead *lp)
  833. {
  834. struct conn *c = LL_ENTRY(lp, struct conn, link);
  835. static const struct vec vec = {"close", 5};
  836. int do_close;
  837. DBG(("Disconnecting %d (%.*s)", c->rem.chan.sock,
  838. c->ch.connection.v_vec.len, c->ch.connection.v_vec.ptr));
  839. if (c->request != NULL && c->ctx->access_log != NULL)
  840. _shttpd_log_access(c->ctx->access_log, c);
  841. /* In inetd mode, exit if request is finished. */
  842. if (IS_TRUE(c->ctx, OPT_INETD))
  843. exit(0);
  844. if (c->loc.io_class != NULL && c->loc.io_class->close != NULL)
  845. c->loc.io_class->close(&c->loc);
  846. /*
  847. * Check the "Connection: " header before we free c->request
  848. * If it its 'keep-alive', then do not close the connection
  849. */
  850. do_close = (c->ch.connection.v_vec.len >= vec.len &&
  851. !_shttpd_strncasecmp(vec.ptr,c->ch.connection.v_vec.ptr,vec.len)) ||
  852. (c->major_version < 1 ||
  853. (c->major_version >= 1 && c->minor_version < 1));
  854. if (c->request)
  855. free(c->request);
  856. if (c->uri)
  857. free(c->uri);
  858. /* Keep the connection open only if we have Content-Length set */
  859. if (!do_close && c->loc.content_len > 0) {
  860. c->loc.io_class = NULL;
  861. c->loc.flags = 0;
  862. c->loc.content_len = 0;
  863. c->rem.flags = FLAG_W | FLAG_R | FLAG_SSL_ACCEPTED;
  864. c->query = c->request = c->uri = c->path_info = NULL;
  865. c->mime_type.len = 0;
  866. (void) memset(&c->ch, 0, sizeof(c->ch));
  867. io_clear(&c->loc.io);
  868. c->birth_time = _shttpd_current_time;
  869. if (io_data_len(&c->rem.io) > 0)
  870. process_connection(c, 0, 0);
  871. } else {
  872. if (c->rem.io_class != NULL)
  873. c->rem.io_class->close(&c->rem);
  874. LL_DEL(&c->link);
  875. c->worker->num_conns--;
  876. assert(c->worker->num_conns >= 0);
  877. free(c);
  878. }
  879. }
  880. static void
  881. worker_destructor(struct llhead *lp)
  882. {
  883. struct worker *worker = LL_ENTRY(lp, struct worker, link);
  884. free_list(&worker->connections, connection_desctructor);
  885. free(worker);
  886. }
  887. static int
  888. is_allowed(const struct shttpd_ctx *ctx, const struct usa *usa)
  889. {
  890. const struct acl *acl;
  891. const struct llhead *lp;
  892. int allowed = '+';
  893. uint32_t ip;
  894. LL_FOREACH(&ctx->acl, lp) {
  895. acl = LL_ENTRY(lp, struct acl, link);
  896. (void) memcpy(&ip, &usa->u.sin.sin_addr, sizeof(ip));
  897. if (acl->ip == (ntohl(ip) & acl->mask))
  898. allowed = acl->flag;
  899. }
  900. return (allowed == '+');
  901. }
  902. static void
  903. add_to_set(int fd, fd_set *set, int *max_fd)
  904. {
  905. FD_SET(fd, set);
  906. if (fd > *max_fd)
  907. *max_fd = fd;
  908. }
  909. static void
  910. process_connection(struct conn *c, int remote_ready, int local_ready)
  911. {
  912. /* Read from remote end if it is ready */
  913. if (remote_ready && io_space_len(&c->rem.io))
  914. read_stream(&c->rem);
  915. /* If the request is not parsed yet, do so */
  916. if (!(c->rem.flags & FLAG_HEADERS_PARSED))
  917. parse_http_request(c);
  918. DBG(("loc: %d [%.*s]", (int) io_data_len(&c->loc.io),
  919. (int) io_data_len(&c->loc.io), io_data(&c->loc.io)));
  920. DBG(("rem: %d [%.*s]", (int) io_data_len(&c->rem.io),
  921. (int) io_data_len(&c->rem.io), io_data(&c->rem.io)));
  922. /* Read from the local end if it is ready */
  923. if (local_ready && io_space_len(&c->loc.io))
  924. read_stream(&c->loc);
  925. if (io_data_len(&c->rem.io) > 0 && (c->loc.flags & FLAG_W) &&
  926. c->loc.io_class != NULL && c->loc.io_class->write != NULL)
  927. write_stream(&c->rem, &c->loc);
  928. if (io_data_len(&c->loc.io) > 0 && c->rem.io_class != NULL)
  929. write_stream(&c->loc, &c->rem);
  930. /* Check whether we should close this connection */
  931. if ((_shttpd_current_time > c->expire_time) ||
  932. (c->rem.flags & FLAG_CLOSED) ||
  933. ((c->loc.flags & FLAG_CLOSED) && !io_data_len(&c->loc.io)))
  934. connection_desctructor(&c->link);
  935. }
  936. static int
  937. num_workers(const struct shttpd_ctx *ctx)
  938. {
  939. char *p = ctx->options[OPT_THREADS];
  940. return (p ? atoi(p) : 1);
  941. }
  942. static void
  943. handle_connected_socket(struct shttpd_ctx *ctx,
  944. struct usa *sap, int sock, int is_ssl)
  945. {
  946. #if !defined(_WIN32)
  947. if (sock >= (int) FD_SETSIZE) {
  948. _shttpd_elog(E_LOG, NULL, "ctx %p: discarding "
  949. "socket %d, too busy", ctx, sock);
  950. (void) closesocket(sock);
  951. } else
  952. #endif /* !_WIN32 */
  953. if (!is_allowed(ctx, sap)) {
  954. _shttpd_elog(E_LOG, NULL, "%s is not allowed to connect",
  955. inet_ntoa(sap->u.sin.sin_addr));
  956. (void) closesocket(sock);
  957. } else if (num_workers(ctx) > 1) {
  958. pass_socket(ctx, sock, is_ssl);
  959. } else {
  960. add_socket(first_worker(ctx), sock, is_ssl);
  961. }
  962. }
  963. static int
  964. do_select(int max_fd, fd_set *read_set, fd_set *write_set, int milliseconds)
  965. {
  966. struct timeval tv;
  967. int n;
  968. tv.tv_sec = milliseconds / 1000;
  969. tv.tv_usec = (milliseconds % 1000) * 1000;
  970. /* Check IO readiness */
  971. if ((n = select(max_fd + 1, read_set, write_set, NULL, &tv)) < 0) {
  972. #ifdef _WIN32
  973. /*
  974. * On windows, if read_set and write_set are empty,
  975. * select() returns "Invalid parameter" error
  976. * (at least on my Windows XP Pro). So in this case,
  977. * we sleep here.
  978. */
  979. Sleep(milliseconds);
  980. #endif /* _WIN32 */
  981. DBG(("select: %d", ERRNO));
  982. }
  983. return (n);
  984. }
  985. static int
  986. multiplex_worker_sockets(const struct worker *worker, int *max_fd,
  987. fd_set *read_set, fd_set *write_set)
  988. {
  989. struct llhead *lp;
  990. struct conn *c;
  991. int nowait = FALSE;
  992. /* Add control socket */
  993. add_to_set(worker->ctl[0], read_set, max_fd);
  994. /* Multiplex streams */
  995. LL_FOREACH(&worker->connections, lp) {
  996. c = LL_ENTRY(lp, struct conn, link);
  997. /* If there is a space in remote IO, check remote socket */
  998. if (io_space_len(&c->rem.io))
  999. add_to_set(c->rem.chan.fd, read_set, max_fd);
  1000. #if !defined(NO_CGI)
  1001. /*
  1002. * If there is a space in local IO, and local endpoint is
  1003. * CGI, check local socket for read availability
  1004. */
  1005. if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) &&
  1006. c->loc.io_class == &_shttpd_io_cgi)
  1007. add_to_set(c->loc.chan.fd, read_set, max_fd);
  1008. /*
  1009. * If there is some data read from remote socket, and
  1010. * local endpoint is CGI, check local for write availability
  1011. */
  1012. if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) &&
  1013. c->loc.io_class == &_shttpd_io_cgi)
  1014. add_to_set(c->loc.chan.fd, write_set, max_fd);
  1015. #endif /* NO_CGI */
  1016. /*
  1017. * If there is some data read from local endpoint, check the
  1018. * remote socket for write availability
  1019. */
  1020. if (io_data_len(&c->loc.io) && !(c->loc.flags & FLAG_SUSPEND))
  1021. add_to_set(c->rem.chan.fd, write_set, max_fd);
  1022. /*
  1023. * Set select wait interval to zero if FLAG_ALWAYS_READY set
  1024. */
  1025. if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) &&
  1026. (c->loc.flags & FLAG_ALWAYS_READY))
  1027. nowait = TRUE;
  1028. if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) &&
  1029. (c->loc.flags & FLAG_ALWAYS_READY))
  1030. nowait = TRUE;
  1031. }
  1032. return (nowait);
  1033. }
  1034. int
  1035. shttpd_join(struct shttpd_ctx *ctx,
  1036. fd_set *read_set, fd_set *write_set, int *max_fd)
  1037. {
  1038. struct llhead *lp;
  1039. struct listener *l;
  1040. int nowait = FALSE;
  1041. /* Add listening sockets to the read set */
  1042. LL_FOREACH(&ctx->listeners, lp) {
  1043. l = LL_ENTRY(lp, struct listener, link);
  1044. add_to_set(l->sock, read_set, max_fd);
  1045. DBG(("FD_SET(%d) (listening)", l->sock));
  1046. }
  1047. if (num_workers(ctx) == 1)
  1048. nowait = multiplex_worker_sockets(first_worker(ctx), max_fd,
  1049. read_set, write_set);
  1050. return (nowait);
  1051. }
  1052. static void
  1053. process_worker_sockets(struct worker *worker, fd_set *read_set)
  1054. {
  1055. struct llhead *lp, *tmp;
  1056. int cmd, skt[2], sock = worker->ctl[0];
  1057. struct conn *c;
  1058. /* Check if new socket is passed to us over the control socket */
  1059. if (FD_ISSET(worker->ctl[0], read_set))
  1060. while (recv(sock, (void *) &cmd, sizeof(cmd), 0) == sizeof(cmd))
  1061. switch (cmd) {
  1062. case CTL_PASS_SOCKET:
  1063. (void)recv(sock, (void *) &skt, sizeof(skt), 0);
  1064. add_socket(worker, skt[0], skt[1]);
  1065. break;
  1066. case CTL_WAKEUP:
  1067. (void)recv(sock, (void *) &c, sizeof(c), 0);
  1068. c->loc.flags &= FLAG_SUSPEND;
  1069. break;
  1070. default:
  1071. _shttpd_elog(E_FATAL, NULL, "ctx %p: ctl cmd %d",
  1072. worker->ctx, cmd);
  1073. break;
  1074. }
  1075. /* Process all connections */
  1076. LL_FOREACH_SAFE(&worker->connections, lp, tmp) {
  1077. c = LL_ENTRY(lp, struct conn, link);
  1078. process_connection(c, FD_ISSET(c->rem.chan.sock, read_set),
  1079. c->loc.io_class != NULL &&
  1080. ((c->loc.flags & FLAG_ALWAYS_READY)
  1081. #if !defined(NO_CGI)
  1082. || (c->loc.io_class == &_shttpd_io_cgi &&
  1083. FD_ISSET(c->loc.chan.fd, read_set))
  1084. #endif /* NO_CGI */
  1085. ));
  1086. }
  1087. }
  1088. /*
  1089. * One iteration of server loop. This is the core of the data exchange.
  1090. */
  1091. void
  1092. shttpd_poll(struct shttpd_ctx *ctx, int milliseconds)
  1093. {
  1094. struct llhead *lp;
  1095. struct listener *l;
  1096. fd_set read_set, write_set;
  1097. int sock, max_fd = -1;
  1098. struct usa sa;
  1099. _shttpd_current_time = time(0);
  1100. FD_ZERO(&read_set);
  1101. FD_ZERO(&write_set);
  1102. if (shttpd_join(ctx, &read_set, &write_set, &max_fd))
  1103. milliseconds = 0;
  1104. if (do_select(max_fd, &read_set, &write_set, milliseconds) < 0)
  1105. return;;
  1106. /* Check for incoming connections on listener sockets */
  1107. LL_FOREACH(&ctx->listeners, lp) {
  1108. l = LL_ENTRY(lp, struct listener, link);
  1109. if (!FD_ISSET(l->sock, &read_set))
  1110. continue;
  1111. do {
  1112. sa.len = sizeof(sa.u.sin);
  1113. if ((sock = accept(l->sock, &sa.u.sa, &sa.len)) != -1)
  1114. handle_connected_socket(ctx,&sa,sock,l->is_ssl);
  1115. } while (sock != -1);
  1116. }
  1117. if (num_workers(ctx) == 1)
  1118. process_worker_sockets(first_worker(ctx), &read_set);
  1119. }
  1120. /*
  1121. * Deallocate shttpd object, free up the resources
  1122. */
  1123. void
  1124. shttpd_fini(struct shttpd_ctx *ctx)
  1125. {
  1126. size_t i;
  1127. free_list(&ctx->workers, worker_destructor);
  1128. free_list(&ctx->registered_uris, registered_uri_destructor);
  1129. free_list(&ctx->acl, acl_destructor);
  1130. free_list(&ctx->listeners, listener_destructor);
  1131. #if !defined(NO_SSI)
  1132. free_list(&ctx->ssi_funcs, _shttpd_ssi_func_destructor);
  1133. #endif /* !NO_SSI */
  1134. for (i = 0; i < NELEMS(ctx->options); i++)
  1135. if (ctx->options[i] != NULL)
  1136. free(ctx->options[i]);
  1137. if (ctx->access_log) (void) fclose(ctx->access_log);
  1138. if (ctx->error_log) (void) fclose(ctx->error_log);
  1139. /* TODO: free SSL context */
  1140. free(ctx);
  1141. }
  1142. /*
  1143. * UNIX socketpair() implementation. Why? Because Windows does not have it.
  1144. * Return 0 on success, -1 on error.
  1145. */
  1146. int
  1147. shttpd_socketpair(int sp[2])
  1148. {
  1149. struct sockaddr_in sa;
  1150. int sock, ret = -1;
  1151. socklen_t len = sizeof(sa);
  1152. sp[0] = sp[1] = -1;
  1153. (void) memset(&sa, 0, sizeof(sa));
  1154. sa.sin_family = AF_INET;
  1155. sa.sin_port = htons(0);
  1156. sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  1157. if ((sock = socket(AF_INET, SOCK_STREAM, 0)) != -1 &&
  1158. !bind(sock, (struct sockaddr *) &sa, len) &&
  1159. !listen(sock, 1) &&
  1160. !getsockname(sock, (struct sockaddr *) &sa, &len) &&
  1161. (sp[0] = socket(AF_INET, SOCK_STREAM, 6)) != -1 &&
  1162. !connect(sp[0], (struct sockaddr *) &sa, len) &&
  1163. (sp[1] = accept(sock,(struct sockaddr *) &sa, &len)) != -1) {
  1164. /* Success */
  1165. ret = 0;
  1166. } else {
  1167. /* Failure, close descriptors */
  1168. if (sp[0] != -1)
  1169. (void) closesocket(sp[0]);
  1170. if (sp[1] != -1)
  1171. (void) closesocket(sp[1]);
  1172. }
  1173. (void) closesocket(sock);
  1174. (void) _shttpd_set_non_blocking_mode(sp[0]);
  1175. (void) _shttpd_set_non_blocking_mode(sp[1]);
  1176. #ifndef _WIN32
  1177. (void) fcntl(sp[0], F_SETFD, FD_CLOEXEC);
  1178. (void) fcntl(sp[1], F_SETFD, FD_CLOEXEC);
  1179. #endif /* _WIN32*/
  1180. return (ret);
  1181. }
  1182. static int isbyte(int n) { return (n >= 0 && n <= 255); }
  1183. static int
  1184. set_inetd(struct shttpd_ctx *ctx, const char *flag)
  1185. {
  1186. ctx = NULL; /* Unused */
  1187. if (_shttpd_is_true(flag)) {
  1188. shttpd_set_option(ctx, "ports", NULL);
  1189. (void) freopen("/dev/null", "a", stderr);
  1190. add_socket(first_worker(ctx), 0, 0);
  1191. }
  1192. return (TRUE);
  1193. }
  1194. static int
  1195. set_uid(struct shttpd_ctx *ctx, const char *uid)
  1196. {
  1197. struct passwd *pw;
  1198. ctx = NULL; /* Unused */
  1199. #if !defined(_WIN32)
  1200. if ((pw = getpwnam(uid)) == NULL)
  1201. _shttpd_elog(E_FATAL, 0, "%s: unknown user [%s]", __func__, uid);
  1202. else if (setgid(pw->pw_gid) == -1)
  1203. _shttpd_elog(E_FATAL, NULL, "%s: setgid(%s): %s",
  1204. __func__, uid, strerror(errno));
  1205. else if (setuid(pw->pw_uid) == -1)
  1206. _shttpd_elog(E_FATAL, NULL, "%s: setuid(%s): %s",
  1207. __func__, uid, strerror(errno));
  1208. #endif /* !_WIN32 */
  1209. return (TRUE);
  1210. }
  1211. static int
  1212. set_acl(struct shttpd_ctx *ctx, const char *s)
  1213. {
  1214. struct acl *acl = NULL;
  1215. char flag;
  1216. int len, a, b, c, d, n, mask;
  1217. /* Delete the old ACLs if any */
  1218. free_list(&ctx->acl, acl_destructor);
  1219. FOR_EACH_WORD_IN_LIST(s, len) {
  1220. mask = 32;
  1221. if (sscanf(s, "%c%d.%d.%d.%d%n",&flag,&a,&b,&c,&d,&n) != 5) {
  1222. _shttpd_elog(E_FATAL, NULL, "[%s]: subnet must be "
  1223. "[+|-]x.x.x.x[/x]", s);
  1224. } else if (flag != '+' && flag != '-') {
  1225. _shttpd_elog(E_FATAL, NULL, "flag must be + or -: [%s]", s);
  1226. } else if (!isbyte(a)||!isbyte(b)||!isbyte(c)||!isbyte(d)) {
  1227. _shttpd_elog(E_FATAL, NULL, "bad ip address: [%s]", s);
  1228. } else if ((acl = malloc(sizeof(*acl))) == NULL) {
  1229. _shttpd_elog(E_FATAL, NULL, "%s", "cannot malloc subnet");
  1230. } else if (sscanf(s + n, "/%d", &mask) == 0) {
  1231. /* Do nothing, no mask specified */
  1232. } else if (mask < 0 || mask > 32) {
  1233. _shttpd_elog(E_FATAL, NULL, "bad subnet mask: %d [%s]", n, s);
  1234. }
  1235. acl->ip = (a << 24) | (b << 16) | (c << 8) | d;
  1236. acl->mask = mask ? 0xffffffffU << (32 - mask) : 0;
  1237. acl->flag = flag;
  1238. LL_TAIL(&ctx->acl, &acl->link);
  1239. }
  1240. return (TRUE);
  1241. }
  1242. #ifndef NO_SSL
  1243. /*
  1244. * Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
  1245. */
  1246. static int
  1247. set_ssl(struct shttpd_ctx *ctx, const char *pem)
  1248. {
  1249. SSL_CTX *CTX;
  1250. void *lib;
  1251. struct ssl_func *fp;
  1252. int retval = FALSE;
  1253. /* Load SSL library dynamically */
  1254. if ((lib = dlopen(SSL_LIB, RTLD_LAZY)) == NULL) {
  1255. _shttpd_elog(E_LOG, NULL, "set_ssl: cannot load %s", SSL_LIB);
  1256. return (FALSE);
  1257. }
  1258. for (fp = ssl_sw; fp->name != NULL; fp++)
  1259. if ((fp->ptr.v_void = dlsym(lib, fp->name)) == NULL) {
  1260. _shttpd_elog(E_LOG, NULL,"set_ssl: cannot find %s", fp->name);
  1261. return (FALSE);
  1262. }
  1263. /* Initialize SSL crap */
  1264. SSL_library_init();
  1265. if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL)
  1266. _shttpd_elog(E_LOG, NULL, "SSL_CTX_new error");
  1267. else if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
  1268. _shttpd_elog(E_LOG, NULL, "cannot open %s", pem);
  1269. else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
  1270. _shttpd_elog(E_LOG, NULL, "cannot open %s", pem);
  1271. else
  1272. retval = TRUE;
  1273. ctx->ssl_ctx = CTX;
  1274. return (retval);
  1275. }
  1276. #endif /* NO_SSL */
  1277. static int
  1278. open_log_file(FILE **fpp, const char *path)
  1279. {
  1280. int retval = TRUE;
  1281. if (*fpp != NULL)
  1282. (void) fclose(*fpp);
  1283. if (path == NULL) {
  1284. *fpp = NULL;
  1285. } else if ((*fpp = fopen(path, "a")) == NULL) {
  1286. _shttpd_elog(E_LOG, NULL, "cannot open log file %s: %s",
  1287. path, strerror(errno));
  1288. retval = FALSE;
  1289. }
  1290. return (retval);
  1291. }
  1292. static int set_alog(struct shttpd_ctx *ctx, const char *path) {
  1293. return (open_log_file(&ctx->access_log, path));
  1294. }
  1295. static int set_elog(struct shttpd_ctx *ctx, const char *path) {
  1296. return (open_log_file(&ctx->error_log, path));
  1297. }
  1298. static void show_cfg_page(struct shttpd_arg *arg);
  1299. static int
  1300. set_cfg_uri(struct shttpd_ctx *ctx, const char *uri)
  1301. {
  1302. free_list(&ctx->registered_uris, &registered_uri_destructor);
  1303. if (uri != NULL)
  1304. shttpd_register_uri(ctx, uri, &show_cfg_page, ctx);
  1305. return (TRUE);
  1306. }
  1307. static struct worker *
  1308. add_worker(struct shttpd_ctx *ctx)
  1309. {
  1310. struct worker *worker;
  1311. if ((worker = calloc(1, sizeof(*worker))) == NULL)
  1312. _shttpd_elog(E_FATAL, NULL, "Cannot allocate worker");
  1313. LL_INIT(&worker->connections);
  1314. worker->ctx = ctx;
  1315. (void) shttpd_socketpair(worker->ctl);
  1316. LL_TAIL(&ctx->workers, &worker->link);
  1317. return (worker);
  1318. }
  1319. #if !defined(NO_THREADS)
  1320. static void
  1321. poll_worker(struct worker *worker, int milliseconds)
  1322. {
  1323. fd_set read_set, write_set;
  1324. int max_fd = -1;
  1325. FD_ZERO(&read_set);
  1326. FD_ZERO(&write_set);
  1327. if (multiplex_worker_sockets(worker, &max_fd, &read_set, &write_set))
  1328. milliseconds = 0;
  1329. if (do_select(max_fd, &read_set, &write_set, milliseconds) < 0)
  1330. return;;
  1331. process_worker_sockets(worker, &read_set);
  1332. }
  1333. static void
  1334. worker_function(void *param)
  1335. {
  1336. struct worker *worker = param;
  1337. while (worker->exit_flag == 0)
  1338. poll_worker(worker, 1000 * 10);
  1339. free_list(&worker->connections, connection_desctructor);
  1340. free(worker);
  1341. }
  1342. static int
  1343. set_workers(struct shttpd_ctx *ctx, const char *value)
  1344. {
  1345. int new_num, old_num;
  1346. struct llhead *lp, *tmp;
  1347. struct worker *worker;
  1348. new_num = atoi(value);
  1349. old_num = 0;
  1350. LL_FOREACH(&ctx->workers, lp)
  1351. old_num++;
  1352. if (new_num == 1) {
  1353. if (old_num > 1)
  1354. /* Stop old threads */
  1355. LL_FOREACH_SAFE(&ctx->workers, lp, tmp) {
  1356. worker = LL_ENTRY(lp, struct worker, link);
  1357. LL_DEL(&worker->link);
  1358. worker = LL_ENTRY(lp, struct worker, link);
  1359. worker->exit_flag = 1;
  1360. }
  1361. (void) add_worker(ctx);
  1362. } else {
  1363. /* FIXME: we cannot here reduce the number of threads */
  1364. while (new_num > 1 && new_num > old_num) {
  1365. worker = add_worker(ctx);
  1366. _beginthread(worker_function, 0, worker);
  1367. old_num++;
  1368. }
  1369. }
  1370. return (TRUE);
  1371. }
  1372. #endif /* NO_THREADS */
  1373. static const struct opt {
  1374. int index; /* Index in shttpd_ctx */
  1375. const char *name; /* Option name in config file */
  1376. const char *description; /* Description */
  1377. const char *default_value; /* Default option value */
  1378. int (*setter)(struct shttpd_ctx *, const char *);
  1379. } known_options[] = {
  1380. {OPT_ROOT, "root", "\tWeb root directory", ".", NULL},
  1381. {OPT_INDEX_FILES, "index_files", "Index files", INDEX_FILES, NULL},
  1382. #ifndef NO_SSL
  1383. {OPT_SSL_CERTIFICATE, "ssl_cert", "SSL certificate file", NULL,set_ssl},
  1384. #endif /* NO_SSL */
  1385. {OPT_PORTS, "ports", "Listening ports", LISTENING_PORTS, set_ports},
  1386. {OPT_DIR_LIST, "dir_list", "Directory listing", "yes", NULL},
  1387. {OPT_CFG_URI, "cfg_uri", "Config uri", NULL, set_cfg_uri},
  1388. {OPT_PROTECT, "protect", "URI to htpasswd mapping", NULL, NULL},
  1389. #ifndef NO_CGI
  1390. {OPT_CGI_EXTENSIONS, "cgi_ext", "CGI extensions", CGI_EXT, NULL},
  1391. {OPT_CGI_INTERPRETER, "cgi_interp", "CGI interpreter", NULL, NULL},
  1392. {OPT_CGI_ENVIRONMENT, "cgi_env", "Additional CGI env vars", NULL, NULL},
  1393. #endif /* NO_CGI */
  1394. {OPT_SSI_EXTENSIONS, "ssi_ext", "SSI extensions", SSI_EXT, NULL},
  1395. #ifndef NO_AUTH
  1396. {OPT_AUTH_REALM, "auth_realm", "Authentication domain name",REALM,NULL},
  1397. {OPT_AUTH_GPASSWD, "auth_gpass", "Global passwords file", NULL, NULL},
  1398. {OPT_AUTH_PUT, "auth_PUT", "PUT,DELETE auth file", NULL, NULL},
  1399. #endif /* !NO_AUTH */
  1400. #ifdef _WIN32
  1401. {OPT_SERVICE, "service", "Manage WinNNT service (install"
  1402. "|uninstall)", NULL, _shttpd_set_nt_service},
  1403. {OPT_HIDE, "systray", "Hide console, show icon on systray",
  1404. "no", _shttpd_set_systray},
  1405. #else
  1406. {OPT_INETD, "inetd", "Inetd mode", "no", set_inetd},
  1407. {OPT_UID, "uid", "\tRun as user", NULL, set_uid},
  1408. #endif /* _WIN32 */
  1409. {OPT_ACCESS_LOG, "access_log", "Access log file", NULL, set_alog},
  1410. {OPT_ERROR_LOG, "error_log", "Error log file", NULL, set_elog},
  1411. {OPT_MIME_TYPES, "mime_types", "Additional mime types list", NULL,NULL},
  1412. {OPT_ALIASES, "aliases", "Path=URI mappings", NULL, NULL},
  1413. {OPT_ACL, "acl", "\tAllow/deny IP addresses/subnets", NULL, set_acl},
  1414. #if !defined(NO_THREADS)
  1415. {OPT_THREADS, "threads", "Number of worker threads", "1", set_workers},
  1416. #endif /* !NO_THREADS */
  1417. {-1, NULL, NULL, NULL, NULL}
  1418. };
  1419. static const struct opt *
  1420. find_opt(const char *opt_name)
  1421. {
  1422. int i;
  1423. for (i = 0; known_options[i].name != NULL; i++)
  1424. if (!strcmp(opt_name, known_options[i].name))
  1425. return (known_options + i);
  1426. _shttpd_elog(E_FATAL, NULL, "no such option: [%s]", opt_name);
  1427. /* UNREACHABLE */
  1428. return (NULL);
  1429. }
  1430. int
  1431. shttpd_set_option(struct shttpd_ctx *ctx, const char *opt, const char *val)
  1432. {
  1433. const struct opt *o = find_opt(opt);
  1434. int retval = TRUE;
  1435. /* Call option setter first, so it can use both new and old values */
  1436. if (o->setter != NULL)
  1437. retval = o->setter(ctx, val);
  1438. /* Free old value if any */
  1439. if (ctx->options[o->index] != NULL)
  1440. free(ctx->options[o->index]);
  1441. /* Set new option value */
  1442. ctx->options[o->index] = val ? _shttpd_strdup(val) : NULL;
  1443. return (retval);
  1444. }
  1445. static void
  1446. show_cfg_page(struct shttpd_arg *arg)
  1447. {
  1448. struct shttpd_ctx *ctx = arg->user_data;
  1449. char opt_name[20], value[BUFSIZ];
  1450. const struct opt *o;
  1451. opt_name[0] = value[0] = '\0';
  1452. if (!strcmp(shttpd_get_env(arg, "REQUEST_METHOD"), "POST")) {
  1453. if (arg->flags & SHTTPD_MORE_POST_DATA)
  1454. return;
  1455. (void) shttpd_get_var("o", arg->in.buf, arg->in.len,
  1456. opt_name, sizeof(opt_name));
  1457. (void) shttpd_get_var("v", arg->in.buf, arg->in.len,
  1458. value, sizeof(value));
  1459. shttpd_set_option(ctx, opt_name, value[0] ? value : NULL);
  1460. }
  1461. shttpd_printf(arg, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"
  1462. "<html><body><h1>SHTTPD v. %s</h1>", shttpd_version());
  1463. shttpd_printf(arg, "%s", "<table border=1"
  1464. "<tr><th>Option</th><th>Description</th>"
  1465. "<th colspan=2>Value</th></tr>");
  1466. if (opt_name[0] != '\0' && value[0] != '\0')
  1467. shttpd_printf(arg, "<p style='color: green'>Saved: %s=%s</p>",
  1468. opt_name, value[0] ? value : "NULL");
  1469. for (o = known_options; o->name != NULL; o++) {
  1470. shttpd_printf(arg,
  1471. "<form method=post><tr><td>%s</td><td>%s</td>"
  1472. "<input type=hidden name=o value='%s'>"
  1473. "<td><input type=text name=v value='%s'></td>"
  1474. "<td><input type=submit value=save></td></form></tr>",
  1475. o->name, o->description, o->name,
  1476. ctx->options[o->index] ? ctx->options[o->index] : "");
  1477. }
  1478. shttpd_printf(arg, "%s", "</table></body></html>");
  1479. arg->flags |= SHTTPD_END_OF_OUTPUT;
  1480. }
  1481. /*
  1482. * Show usage string and exit.
  1483. */
  1484. void
  1485. _shttpd_usage(const char *prog)
  1486. {
  1487. const struct opt *o;
  1488. (void) fprintf(stderr,
  1489. "SHTTPD version %s (c) Sergey Lyubka\n"
  1490. "usage: %s [options] [config_file]\n", VERSION, prog);
  1491. #if !defined(NO_AUTH)
  1492. fprintf(stderr, " -A <htpasswd_file> <realm> <user> <passwd>\n");
  1493. #endif /* NO_AUTH */
  1494. for (o = known_options; o->name != NULL; o++) {
  1495. (void) fprintf(stderr, " -%s\t%s", o->name, o->description);
  1496. if (o->default_value != NULL)
  1497. fprintf(stderr, " (default: %s)", o->default_value);
  1498. fputc('\n', stderr);
  1499. }
  1500. exit(EXIT_FAILURE);
  1501. }
  1502. static void
  1503. set_opt(struct shttpd_ctx *ctx, const char *opt, const char *value)
  1504. {
  1505. const struct opt *o;
  1506. o = find_opt(opt);
  1507. if (ctx->options[o->index] != NULL)
  1508. free(ctx->options[o->index]);
  1509. ctx->options[o->index] = _shttpd_strdup(value);
  1510. }
  1511. static void
  1512. process_command_line_arguments(struct shttpd_ctx *ctx, char *argv[])
  1513. {
  1514. const char *config_file = CONFIG_FILE;
  1515. char line[BUFSIZ], opt[BUFSIZ],
  1516. val[BUFSIZ], path[FILENAME_MAX], *p;
  1517. FILE *fp;
  1518. size_t i, line_no = 0;
  1519. /* First find out, which config file to open */
  1520. for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
  1521. if (argv[i + 1] == NULL)
  1522. _shttpd_usage(argv[0]);
  1523. if (argv[i] != NULL && argv[i + 1] != NULL) {
  1524. /* More than one non-option arguments are given w*/
  1525. _shttpd_usage(argv[0]);
  1526. } else if (argv[i] != NULL) {
  1527. /* Just one non-option argument is given, this is config file */
  1528. config_file = argv[i];
  1529. } else {
  1530. /* No config file specified. Look for one where shttpd lives */
  1531. if ((p = strrchr(argv[0], DIRSEP)) != 0) {
  1532. _shttpd_snprintf(path, sizeof(path), "%.*s%s",
  1533. p - argv[0] + 1, argv[0], config_file);
  1534. config_file = path;
  1535. }
  1536. }
  1537. fp = fopen(config_file, "r");
  1538. /* If config file was set in command line and open failed, exit */
  1539. if (fp == NULL && argv[i] != NULL)
  1540. _shttpd_elog(E_FATAL, NULL, "cannot open config file %s: %s",
  1541. config_file, strerror(errno));
  1542. if (fp != NULL) {
  1543. _shttpd_elog(E_LOG, NULL, "Loading config file %s", config_file);
  1544. /* Loop over the lines in config file */
  1545. while (fgets(line, sizeof(line), fp) != NULL) {
  1546. line_no++;
  1547. /* Ignore empty lines and comments */
  1548. if (line[0] == '#' || line[0] == '\n')
  1549. continue;
  1550. if (sscanf(line, "%s %[^\n#]", opt, val) != 2)
  1551. _shttpd_elog(E_FATAL, NULL, "line %d in %s is invalid",
  1552. line_no, config_file);
  1553. set_opt(ctx, opt, val);
  1554. }
  1555. (void) fclose(fp);
  1556. }
  1557. /* Now pass through the command line options */
  1558. for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
  1559. set_opt(ctx, &argv[i][1], argv[i + 1]);
  1560. }
  1561. struct shttpd_ctx *
  1562. shttpd_init(int argc, char *argv[])
  1563. {
  1564. struct shttpd_ctx *ctx;
  1565. struct tm *tm;
  1566. const struct opt *o;
  1567. if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
  1568. _shttpd_elog(E_FATAL, NULL, "cannot allocate shttpd context");
  1569. LL_INIT(&ctx->registered_uris);
  1570. LL_INIT(&ctx->error_handlers);
  1571. LL_INIT(&ctx->acl);
  1572. LL_INIT(&ctx->ssi_funcs);
  1573. LL_INIT(&ctx->listeners);
  1574. LL_INIT(&ctx->workers);
  1575. /* Initialize options. First pass: set default option values */
  1576. for (o = known_options; o->name != NULL; o++)
  1577. ctx->options[o->index] = o->default_value ?
  1578. _shttpd_strdup(o->default_value) : NULL;
  1579. /* Second and third passes: config file and argv */
  1580. if (argc > 0 && argv != NULL)
  1581. process_command_line_arguments(ctx, argv);
  1582. /* Call setter functions */
  1583. for (o = known_options; o->name != NULL; o++)
  1584. if (o->setter && ctx->options[o->index] != NULL)
  1585. if (o->setter(ctx, ctx->options[o->index]) == FALSE) {
  1586. shttpd_fini(ctx);
  1587. return (NULL);
  1588. }
  1589. _shttpd_current_time = time(NULL);
  1590. tm = localtime(&_shttpd_current_time);
  1591. _shttpd_tz_offset = 0;
  1592. if (num_workers(ctx) == 1)
  1593. (void) add_worker(ctx);
  1594. #if 0
  1595. tm->tm_gmtoff - 3600 * (tm->tm_isdst > 0 ? 1 : 0);
  1596. #endif
  1597. #ifdef _WIN32
  1598. {WSADATA data; WSAStartup(MAKEWORD(2,2), &data);}
  1599. #endif /* _WIN32 */
  1600. return (ctx);
  1601. }