commit d1833e88da92d72b30d2a827520ae7c11f335929
parent f9f4bc9c8a388f5f9313bb9810385546049f3643
Author: Remy Noulin <loader2x@gmail.com>
Date: Mon, 13 Nov 2017 08:58:28 +0100
print server url at start
liveserver.c | 2 +
package.yml | 2 +-
server.c | 448 -----------------------------------------------------------
3 files changed, 3 insertions(+), 449 deletions(-)
Diffstat:
3 files changed, 3 insertions(+), 449 deletions(-)
diff --git a/liveserver.c b/liveserver.c
@@ -406,6 +406,8 @@ int main(int argc, char **argv)
dirList = allocG(rtSmallArrayt);
execO("find . -type d", dirList, NULL);
+ printf(GRN "http://0.0.0.0:%s/" RST "\nlog: server.log", portS);
+
if(fork() != 0)
return 0;
(void)signal(SIGCLD, SIG_IGN);
diff --git a/package.yml b/package.yml
@@ -1,6 +1,6 @@
---
name: liveserver
- version: 0.0.3
+ version: 0.0.4
description: "simple web server that reloads when file updates are detected"
bin: ./liveserver.c
repository:
diff --git a/server.c b/server.c
@@ -1,448 +0,0 @@
-#! /usr/bin/env sheepy
-
-/*
- * project: miniweb
- * author: Oscar Sanchez (oms1005@gmail.com)
- * HTTP Server
- * WORKS ON BROWSERS TOO!
- * Inspired by IBM's nweb
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include "inoty.h"
-
-#include "libsheepyObject.h"
-#include "utilities.h"
-
-#define BUFSIZE 8096
-#define ERROR 42
-#define SORRY 43
-#define LOG 44
-
-i64 waitTime = 0;
-
-smallArrayt *dirList;
-
-const char injected[] = "<!-- Code injected by live-server -->\n\
-<script type=\"text/javascript\">\n\
- // <![CDATA[ <-- For SVG support\n\
- if ('WebSocket' in window) {\n\
- (function() {\n\
- function refreshCSS() {\n\
- var sheets = [].slice.call(document.getElementsByTagName(\"link\"));\n\
- var head = document.getElementsByTagName(\"head\")[0];\n\
- for (var i = 0; i < sheets.length; ++i) {\n\
- var elem = sheets[i];\n\
- head.removeChild(elem);\n\
- var rel = elem.rel;\n\
- if (elem.href && typeof rel != \"string\" || rel.length == 0 || rel.toLowerCase() == \"stylesheet\") {\n\
- var url = elem.href.replace(/(&|\\?)_cacheOverride=\\d+/, '');\n\
- elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());\n\
- }\n\
- head.appendChild(elem);\n\
- }\n\
- }\n\
- var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';\n\
- var address = protocol + window.location.host + window.location.pathname + '/ws';\n\
- var socket = new WebSocket(address);\n\
- socket.onmessage = function(msg) {\n\
- if (msg.data == 'reload') window.location.reload();\n\
- else if (msg.data == 'refreshcss') refreshCSS();\n\
- };\n\
- console.log('Live reload enabled.');\n\
- })();\n\
- }\n\
- // ]]>\n\
-</script>\n\
-";
-
-struct {
- char *ext;
- char *filetype;
-} extensions [] = {
- {"gif", "image/gif" },
- {"jpg", "image/jpeg"},
- {"jpeg","image/jpeg"},
- {"png", "image/png" },
- {"zip", "image/zip" },
- {"gz", "image/gz" },
- {"tar", "image/tar" },
- {"htm", "text/html" },
- {"html","text/html" },
- {"php", "image/php" },
- {"cgi", "text/cgi" },
- {"asp", "text/asp" },
- {"jsp", "image/jsp" },
- {"xml", "text/xml" },
- {"js", "text/js" },
- {"css", "text/css" },
- {"//ws", "websocket"},
-
- {0,0} };
-
-#define WEBSOCKET_SERVER_RESPONSE "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
-
-#define WEBSOCK_PACKAGE_NAME "s"
-#define WEBSOCK_PACKAGE_VERSION "0"
-
-void slog(int type, char *s1, char *s2, int num)
-{
- int fd ;
- char logbuffer[BUFSIZE*2];
-
- switch (type) {
- case ERROR: (void)sprintf(logbuffer,"ERROR: %s:%s Errno=%d exiting pid=%d",s1, s2, errno,getpid()); break;
- case SORRY:
- (void)sprintf(logbuffer, "<HTML><BODY><H1>Web Server Sorry: %s %s</H1></BODY></HTML>\r\n", s1, s2);
- (void)write(num,logbuffer,strlen(logbuffer));
- (void)sprintf(logbuffer,"SORRY: %s:%s",s1, s2);
- break;
- case LOG: (void)sprintf(logbuffer," INFO: %s:%s:%d",s1, s2,num); break;
- }
-
- if((fd = open("server.log", O_CREAT| O_WRONLY | O_APPEND,0644)) >= 0) {
- (void)write(fd,logbuffer,strlen(logbuffer));
- (void)write(fd,"\n",1);
- (void)close(fd);
- }
- if(type == ERROR || type == SORRY) exit(3);
-}
-
-void web(int fd, int hit)
-{
- int j, file_fd, buflen, len;
- long i, ret;
- char * fstr;
- static char buffer[BUFSIZE+1];
-
- ret =read(fd,buffer,BUFSIZE);
- if(ret == 0 || ret == -1) {
- slog(SORRY,"failed to read browser request","",fd);
- }
- if(ret > 0 && ret < BUFSIZE)
- buffer[ret]=0;
- else buffer[0]=0;
-
- smallStringt *reqS = allocG(buffer);
- smallArrayt *req = splitG(reqS, "\r\n");
- char *clientKey = NULL;
- char *origin = NULL;
- char *protocol = NULL; // protocol not parsed, firefox 52 doesnt send it
- forEachSmallArray(req, S) {
- castS(s,S);
- if (startsWithG(s, "Sec-WebSocket-Key:")) {
- clientKey = ssGet(s) + 19;
- }
- if(startsWithSG(s, "Origin:")) {
- origin = ssGet(s) + 8;
- }
- finishG(s);
- }
-
- for(i=0;i<ret;i++)
- if(buffer[i] == '\r' || buffer[i] == '\n')
- buffer[i]='*';
- slog(LOG,"request",buffer,hit);
-
- if( strncmp(buffer,"GET ",4) && strncmp(buffer,"get ",4) )
- slog(SORRY,"Only simple GET operation supported",buffer,fd);
-
- for(i=4;i<BUFSIZE;i++) {
- if(buffer[i] == ' ') {
- buffer[i] = 0;
- break;
- }
- }
-
- for(j=0;j<i-1;j++)
- if(buffer[j] == '.' && buffer[j+1] == '.')
- slog(SORRY,"Parent directory (..) path names not supported",buffer,fd);
-
- if( !strncmp(&buffer[0],"GET /\0",6) || !strncmp(&buffer[0],"get /\0",6) )
- (void)strcpy(buffer,"GET /index.html");
-
- bool isHTML = false;
- bool isWebsocket = false;
-
- buflen=strlen(buffer);
- fstr = (char *)0;
- for(i=0;extensions[i].ext != 0;i++) {
- len = strlen(extensions[i].ext);
- if( !strncmp(&buffer[buflen-len], extensions[i].ext, len)) {
- fstr =extensions[i].filetype;
- if (startsWithG(extensions[i].ext, "htm")) isHTML = true;
- else if (eqS(extensions[i].ext, "//ws")) isWebsocket = true;
- break;
- }
- }
- if(fstr == 0) slog(SORRY,"file extension type not supported",buffer,fd);
-
- if (isWebsocket) {
- // WEBSOCKET HANDLING
-
- slog(LOG,"websocket","detected",hit);
- slog(LOG,"key",clientKey,hit);
-
- SHA1Context shactx;
- SHA1Reset(&shactx);
-
- char buf[1024];
- sprintf(buf, "%s%s", clientKey, WEBSOCKET_SERVER_RESPONSE);
-
- SHA1Input(&shactx, (unsigned char *) buf, strlen(buf));
- SHA1Result(&shactx);
-
- char sha1buf[45];
- unsigned char sha1mac[20];
-
- sprintf(sha1buf, "%08x%08x%08x%08x%08x", shactx.Message_Digest[0],
- shactx.Message_Digest[1], shactx.Message_Digest[2],
- shactx.Message_Digest[3], shactx.Message_Digest[4]);
-
- for (i16 n = 0; n < (strlen(sha1buf) / 2); n++) {
- sscanf(sha1buf + (n * 2), "%02hhx", sha1mac + n);
- }
-
- char base64buf[256];
- base64_encode(sha1mac, 20, base64buf, 256);
- memset(buf, 0, 1024);
- snprintf(buf, 1024, "HTTP/1.1 101 Switching Protocols\r\n"
- "Server: %s/%s\r\n"
- "Upgrade: websocket\r\n"
- "%s%s%s"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: %s\r\n%s%s"
- "Access-Control-Allow-Headers: content-type\r\n\r\n", WEBSOCK_PACKAGE_NAME,
- WEBSOCK_PACKAGE_VERSION, origin ? "Access-Control-Allow-Origin: " : "", origin ? origin : "", origin ? "\r\n" : "", base64buf, protocol ? protocol : "", protocol ? "\r\n" : "");
-
- (void)write(fd,buf,strlen(buf));
-
- // INOTIFY SETUP
-
- // wait for changes and reload page
- enum {yes, no};
- i8 foundRelevantUpdate = no;
- while (foundRelevantUpdate == no) {
- // creating the INOTIFY instance
- int length;
- char ibuffer[EVENT_BUF_LEN];
- int ifd = inotiFy_init();
- if (ifd == -1) {
- perror("inotiFy_init error: ");
- }
-
- int wd; // watch descriptor
-
- forEachSmallArray(dirList, E) {
- castS(e, E);
- wd = inotiFy_add_watch( ifd, ssGet(e), IN_CREATE | IN_DELETE | IN_MODIFY);
- finishG(e);
- }
-
- // read to determine the event change happens on “.” directory. Actually this read blocks until the change event occurs
- length = read( ifd, ibuffer, EVENT_BUF_LEN );;
-
- if (length == -1) {
- perror("read error: ");
- }
-
- u32 i = 0;
- // actually read return the list of change events happens. Here, read the change event one by one and process it accordingly.
- while (( i < length )) {
- struct inotiFy_event *event = ( struct inotiFy_event * ) &ibuffer[ i ];
-
- for(i=0;extensions[i].ext != 0;i++) {
- if (endsWithG(event->name, extensions[i].ext)) {
- if ((event->mask & IN_CREATE) || (event->mask & IN_DELETE) || (event->mask & IN_MODIFY)) {
- foundRelevantUpdate = yes;
- }
- }
- }
-
- i += EVENT_SIZE + event->len;
- }
-
-
- // removing the “/tmp” directory from the watch list.
- inotiFy_rm_watch( ifd, wd );
-
- // closing the INOTIFY instance
- close(ifd);
- }
-
- if (waitTime > 0) {
- // wait before reloading
- sleep(waitTime);
- }
-
- // WEBSOCKET SEND RELOAD TO CLIENT
-
- // send reload
- u32 fin = 1;
- u32 op = 1;
- u32 plen = 6;
- u32 blen = plen+2;
-
- buf[0] = (1 << 7) + fin; // 0x81
- buf[1] = plen;
- /* uint16_t *b = (uint16_t*)buf; */
- /* *b = (plen << 9) + (op << 4) + fin; */
- strcpy(buf+2, "reload");
-
- (void)write(fd,buf,blen);
- } else {
-
- // SERVE REGULAR HTTP REQUESTS
-
- char *serveFile = &buffer[5];
-
- if (isHTML) {
- size_t endBodyAt = 0;
- createAllocateSmallArray(f);
- readFileG(f, &buffer[5]);
- enumerateSmallArray(f, S, n) {
- castS(s, S);
- if (hasG(lowerG(s), "</body>")) {
- endBodyAt = n;
- finishG(s);
- break;
- }
- finishG(s);
- }
- injectSG(f, endBodyAt, injected);
- writeFileG(f, "a");
- terminateG(f);
- serveFile = "a";
- }
-
- if(( file_fd = open(serveFile,O_RDONLY)) == -1)
- slog(SORRY, "failed to open file",serveFile,fd);
-
- slog(LOG,"SEND",serveFile,hit);
-
- (void)sprintf(buffer,"HTTP/1.0 200 OK\r\nContent-Type: %s\r\n\r\n", fstr);
- (void)write(fd,buffer,strlen(buffer));
-
- while ((ret = read(file_fd, buffer, BUFSIZE)) > 0 ) {
- (void)write(fd,buffer,ret);
- }
- }
-
- terminateManyG(reqS, req);
-
-#ifdef LINUX
- sleep(1);
-#endif
- exit(1);
-}
-
-
-int main(int argc, char **argv)
-{
- int i, port, pid, listenfd, socketfd, hit;
- size_t length;
- static struct sockaddr_in cli_addr;
- static struct sockaddr_in serv_addr;
- char *portS;
- char *dir = NULL;
-
- // defaults
- port = 8080;
- portS = "8080";
-
- forEachS(argv, a) {
- if (startsWithG(a, "-port=")) {
- portS = a+6;
- port = parseInt(portS);
- }
- else if (startsWithG(a, "-path=")) {
- dir = a+6;
- }
- else if (startsWithG(a, "-wait=")) {
- waitTime = parseInt(a+6);
- }
- else if (startsWithG(a, "--help") or startsWithG(a, "-h") or startsWithG(a, "-?")) {
- printf("usage: server [-port=80] [-path=server_directory] [-wait=1]\n"
- "\twait unit is second.\n"
- "\tExample: server -port=8080 -path=./ -wait=1\n\n"
- "\tOnly Supports:");
- for(i=0;extensions[i].ext != 0;i++)
- (void)printf(" %s",extensions[i].ext);
-
- (void)printf("\n\tNot Supported: directories / /etc /bin /lib /tmp /usr /dev /sbin \n"
- );
- XSUCCESS
- }
- }
-
- if (dir) {
- if( !strncmp(dir,"/" ,2 ) || !strncmp(dir,"/etc", 5 ) ||
- !strncmp(dir,"/bin",5 ) || !strncmp(dir,"/lib", 5 ) ||
- !strncmp(dir,"/tmp",5 ) || !strncmp(dir,"/usr", 5 ) ||
- !strncmp(dir,"/dev",5 ) || !strncmp(dir,"/sbin",6) ){
- (void)printf("ERROR: Bad top directory %s, see server -?\n",dir);
- exit(3);
- }
- if(chdir(dir) == -1){
- (void)printf("ERROR: Can't Change to directory %s\n",dir);
- exit(4);
- }
- }
-
- dirList = allocG(rtSmallArrayt);
- execO("find . -type d", dirList, NULL);
-
- if(fork() != 0)
- return 0;
- (void)signal(SIGCLD, SIG_IGN);
- (void)signal(SIGHUP, SIG_IGN);
- for(i=0;i<32;i++)
- (void)close(i);
- (void)setpgrp();
-
- slog(LOG,"http server starting",portS,getpid());
-
- if((listenfd = socket(AF_INET, SOCK_STREAM,0)) <0)
- slog(ERROR, "system call","socket",0);
-
- if(port < 0 || port >60000)
- slog(ERROR,"Invalid port number try [1,60000]",portS,0);
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- serv_addr.sin_port = htons(port);
- if(bind(listenfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) <0)
- slog(ERROR,"system call","bind",0);
- if( listen(listenfd,64) <0)
- slog(ERROR,"system call","listen",0);
-
- for(hit=1; ;hit++) {
- length = sizeof(cli_addr);
- if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, (socklen_t *)&length)) < 0)
- slog(ERROR,"system call","accept",0);
-
- if((pid = fork()) < 0) {
- slog(ERROR,"system call","fork",0);
- }
- else {
- if(pid == 0) {
- (void)close(listenfd);
- web(socketfd,hit);
- } else {
- (void)close(socketfd);
- }
- }
- }
-
- terminateG(dirList);
-
-}