List of commits:
Subject Hash Author Date (UTC)
content-type support 30ab51cd0ae1f9a3ebb55ca145b1ad8c1221533c root 2016-04-28 23:39:07
typo fix, thx Florian Bruhin from suckless 4bd12dd5d83edf9c216f470098341529e3c31a3e Sylvain BERTRAND 2016-04-20 14:27:01
handle other side closed connection (0 bytes read) 019e89b4327f902dd6d28264cda5f114b67172e4 Sylvain BERTRAND 2016-04-20 14:00:40
working enough for my personnal use 905534989172399ceb39502913c24ea51e5daf42 Sylvain BERTRAND 2016-04-20 00:13:48
Initial commit 143cb38e968fd7384da0d66a3cedee87c12852cc Sylvain BERTRAND 2016-04-20 00:04:50
Commit 30ab51cd0ae1f9a3ebb55ca145b1ad8c1221533c - content-type support
Author: root
Author date (UTC): 2016-04-28 23:39
Committer name: root
Committer date (UTC): 2016-04-28 23:39
Parent(s): 4bd12dd5d83edf9c216f470098341529e3c31a3e
Signing key:
Tree: d0cb92a046068b1f44b3adc3469815dccd9c60da
File Lines added Lines deleted
README 4 1
lnanohttp.c 111 6
File README changed (mode: 100644) (index 2876340..b52076f)
... ... This is another _really_ minimal ISO C90-ish http server for linux:
7 7
8 8 Only HEAD and GET methods. Only HEAD and GET methods.
9 9
10 Rely on user agent content type detection.
10 To map a content-type to a file "A", add a file "A.mime" containing the
11 content-type. You don't need to add a charset to utf-8 xml target since the
12 http default iso8859-1 allows the browser to parse the xml first element were
13 utf-8 encoding will be defined.
11 14
12 15 Will chroot in the configured path once started. Will chroot in the configured path once started.
13 16
File lnanohttp.c changed (mode: 100644) (index 634db75..8116863)
39 39 /* 32 bits value for the IPv4, can be INADDR_ANY */ /* 32 bits value for the IPv4, can be INADDR_ANY */
40 40 #define LISTENING_IPV4 INADDR_ANY #define LISTENING_IPV4 INADDR_ANY
41 41 /* the chroot patch used upon start */ /* the chroot patch used upon start */
42 #define CHROOT_PATH "/home/sylvain/wip/bn/chroot"
42 #define CHROOT_PATH "/root/http/chroot"
43 43 /* time out for a socket read/write, in seconds. 4 secs is huge */ /* time out for a socket read/write, in seconds. 4 secs is huge */
44 44 #define CNX_WAIT_TIMEOUT 4 #define CNX_WAIT_TIMEOUT 4
45 45 /* default file */ /* default file */
46 46 #define DEFAULT_FILE (u8*)"/index.xhtml" #define DEFAULT_FILE (u8*)"/index.xhtml"
47 #define DEFAULT_FILE_MIME (u8*)"/index.xhtml.mime"
47 48
48 /* XXX:Rely on user agent content type detection.
49 For more content type accuracy, the next step would be a mapping between
50 the file paths and the content types.*/
51 49 #define RESP_HDR_FMT (u8*)"\ #define RESP_HDR_FMT (u8*)"\
52 50 HTTP/1.1 200 \r\n\ HTTP/1.1 200 \r\n\
53 51 content-length:%u\r\n\r\n" content-length:%u\r\n\r\n"
52
53 #define RESP_HDR_CONTENT_TYPE_FMT (u8*)"\
54 HTTP/1.1 200 \r\n\
55 content-length:%u\r\n\
56 content-type:%s\r\n\r\n"
54 57 /******************************************************************************/ /******************************************************************************/
55 58
56 59 #define SIGBIT(sig) (1<<(sig-1)) #define SIGBIT(sig) (1<<(sig-1))
 
... ... static ul page_bytes_rd_n; /* keep an eye on how much was read */
85 88
86 89 static u8 *method_target_space; static u8 *method_target_space;
87 90 static u8 *target_start; static u8 *target_start;
88 static u8 *target_end;
91 static u8 *target_end; /* point the space char right after */
89 92 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
90 93
91 94 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
95 static u8 target_file_is_default;
92 96 static si target_file_fd; static si target_file_fd;
93 97 static ul target_file_sz; static ul target_file_sz;
98 static u8 target_file_mime[255 + 1]; /* actually the content-type */
94 99 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
95 100
96 101 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
 
... ... static sl cnx_sock_send_resp_hdr(void)
373 378
374 379 static u8 http_resp_hdr_send(void) static u8 http_resp_hdr_send(void)
375 380 { {
376 resp_hdr_sz = (sl)snprintf(page, PAGE_SZ, RESP_HDR_FMT, target_file_sz);
381 if (target_file_mime[0] == 0)
382 resp_hdr_sz = (sl)snprintf(page, PAGE_SZ, RESP_HDR_FMT,
383 target_file_sz);
384 else
385 resp_hdr_sz = (sl)snprintf(page, PAGE_SZ,
386 RESP_HDR_CONTENT_TYPE_FMT,
387 target_file_sz,
388 &target_file_mime[0]);
377 389
378 390 if (resp_hdr_sz == 0) if (resp_hdr_sz == 0)
379 391 return HTTP_CLOSE; return HTTP_CLOSE;
 
... ... static u8 http_sendfile(void)
437 449 return HTTP_CLOSE; return HTTP_CLOSE;
438 450 } }
439 451
452 static u8 *http_target_mime_file_path(void)
453 {
454 /* We have room in the page. target_end has not be modified */
455 target_end[0] = '.';
456 target_end[1] = 'm';
457 target_end[2] = 'i';
458 target_end[3] = 'm';
459 target_end[4] = 'e';
460 target_end[5] = 0;
461 return target_start;
462 }
463
464 static void http_target_mime_file(void)
465 {
466 u8 *mime_file_path;
467 sl r;
468 si mime_file_fd;
469 struct stat mime_file_stat;
470 ul bytes_to_read_n;
471
472 if (target_file_is_default)
473 mime_file_path = DEFAULT_FILE_MIME;
474 else
475 mime_file_path = http_target_mime_file_path();
476
477 /*--------------------------------------------------------------------*/
478 /* open */
479 loop {
480 r = open(mime_file_path, O_RDONLY, 0);
481 if (r != -EINTR)
482 break;
483 }
484 if (ISERR(r))
485 goto direct_exit;
486
487 mime_file_fd = (si)r;
488 /*--------------------------------------------------------------------*/
489
490 /*--------------------------------------------------------------------*/
491 /* get size */
492 memset(&mime_file_stat, 0, sizeof(mime_file_stat));
493
494 r = fstat(mime_file_fd, &mime_file_stat);
495 if (ISERR(r))
496 goto direct_exit;
497
498 /* mime_file_stat.sz */
499 /*--------------------------------------------------------------------*/
500
501 /*--------------------------------------------------------------------*/
502 /* check size */
503 if ((mime_file_stat.sz + 1) > sizeof(target_file_mime)) {
504 r = -1;
505 goto direct_exit;
506 }
507 bytes_to_read_n = mime_file_stat.sz;
508 /*--------------------------------------------------------------------*/
509
510 /*--------------------------------------------------------------------*/
511 /* read it */
512 loop {
513 r = read(mime_file_fd, &target_file_mime[0] + mime_file_stat.sz
514 - bytes_to_read_n, bytes_to_read_n);
515 if (r != -EINTR) {
516 if (ISERR(r))
517 goto close_mime_file;
518
519 bytes_to_read_n -= r;
520
521 if (bytes_to_read_n == 0)
522 break;
523 }
524 }
525 /*--------------------------------------------------------------------*/
526
527 target_file_mime[mime_file_stat.sz] = 0;
528
529 close_mime_file:
530 close(mime_file_fd);
531
532 direct_exit:
533 if (ISERR(r))
534 target_file_mime[0] = 0; /* no mime */
535 }
536
440 537 /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
441 538
442 539 static void cnx_handle(void) static void cnx_handle(void)
 
... ... static void cnx_handle(void)
462 559 if (r == HTTP_CLOSE) if (r == HTTP_CLOSE)
463 560 goto direct_exit; goto direct_exit;
464 561
562 /* now we check we have room for the ".mime" extension */
563 if ((target_end - 1 + sizeof(".mime")) >= (page + PAGE_SZ))
564 goto direct_exit;
565
465 566 /* target is exactly "/" or prepare the path */ /* target is exactly "/" or prepare the path */
466 567 if ((target_end - (method_target_space + 1)) == 1 if ((target_end - (method_target_space + 1)) == 1
467 568 && method_target_space[1] == '/') { && method_target_space[1] == '/') {
569 target_file_is_default = 1;
468 570 target_start = DEFAULT_FILE; target_start = DEFAULT_FILE;
469 571 } else { } else {
572 target_file_is_default = 0;
470 573 target_start = method_target_space + 1; target_start = method_target_space + 1;
471 574 *target_end = 0; *target_end = 0;
472 575 } }
 
... ... static void cnx_handle(void)
479 582 if (r == HTTP_CLOSE) if (r == HTTP_CLOSE)
480 583 goto close_target_file; goto close_target_file;
481 584
585 http_target_mime_file();
586
482 587 r = http_resp_hdr_send(); r = http_resp_hdr_send();
483 588 if (r == HTTP_CLOSE) if (r == HTTP_CLOSE)
484 589 goto close_target_file; goto close_target_file;
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/sylware/lnanohttp

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/sylware/lnanohttp

Clone this repository using git:
git clone git://git.rocketgit.com/user/sylware/lnanohttp

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main