예제 #1
0
/** Process an incoming GUI request
	@returns non-zero on success, 0 on failure (errno set)
 **/
int http_gui_request(HTTP *http,char *uri)
{
	gui_set_html_stream((void*)http,http_format);
	if (gui_html_output_page(uri)>=0)
	{
		http_type(http,"text/html");
		return 1;
	}
	else 
		return 0;
}
예제 #2
0
/** Process an incoming action request
	@returns non-zero on success, 0 on failure (errno set)
 **/
int http_action_request(HTTP *http,char *action)
{
	if (gui_post_action(action)==-1)
	{
		http_status(http,HTTP_ACCEPTED);
		http_type(http,"text/plain");
		http_format(http,"Goodbye");
		http_send(http);
		http_close(http);
		shutdown_now();
		return 1;
	}
	else
		return 0;
}
예제 #3
0
/*
 * Handles an HTTP error.
 */
void http_error(socket_t s, unsigned http_code,
    const struct http_request_s *request)
{
    const char *content_filename;
    switch (http_code)
    {
        case 404:
            content_filename = "404.html";
            break;
        case 500:
            content_filename = "500.html";
            break;
        default:
            panic("unsupported HTTP code %u", http_code);
    }

    if (http_type(request->name) == HTTP_TYPE_HTML)
    {
        http_buffer_t content = http_lookup_content(content_filename);
        if (content != NULL)
        {
            if (http_send_response(s, http_code, content, request))
            {
                http_buffer_close(content);
                return;
            }
            http_buffer_close(content);
        }
    }

    // Emergency fall back:
    static const char http_header[] =
        "HTTP/1.1 500 Internal Server Error\r\n"
        "Connection: close\r\n"
        "\r\n";
    size_t http_header_length = sizeof(http_header)-1;
    if (send(s, http_header, http_header_length, 0) != http_header_length)
    {
        warning("unable to send HTTP 500 response of size " SIZE_T_FMT
            " bytes", http_header_length);
    }
}
예제 #4
0
/** Process an incoming XML data request
	@returns non-zero on success, 0 on failure (errno set)
 **/
int http_xml_request(HTTP *http,char *uri)
{
	char arg1[1024]="", arg2[1024]="";
	int nargs = sscanf(uri,"%1023[^/=\r\n]/%1023[^\r\n=]",arg1,arg2);
	char *value = strchr(uri,'=');
	char buffer[1024]="";
	OBJECT *obj=NULL;
	char *id;

	/* value */
	if (value) *value++;

	/* decode %.. */
	http_decode(arg1);
	http_decode(arg2);
	if (value) http_decode(value);

	/* process request */
	switch (nargs) {

	/* get global variable */
	case 1: 

		/* find the variable */
		if (global_getvar(arg1,buffer,sizeof(buffer))==NULL)
		{
			output_error("global variable '%s' not found", arg1);
			return 0;
		}

		/* assignment, if any */
		if (value) global_setvar(arg1,value);
		
		/* post the response */
		http_format(http,"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
		http_format(http,"<globalvar>\n\t<name>%s</name>\n\t<value>%s</value>\n</globalvar>\n",
			arg1, http_unquote(buffer));
		http_type(http,"text/xml");
		return 1;

	/* get object property */
	case 2:

		/* find the object */
		id = strchr(arg1,':');
		if ( id==NULL )
			obj = object_find_name(arg1);
		else
			obj = object_find_by_id(atoi(id+1));
		if ( obj==NULL )
		{
			output_error("object '%s' not found", arg1);
			return 0;
		}

		/* post the current value */
		if ( !object_get_value_by_name(obj,arg2,buffer,sizeof(buffer)) )
		{
			output_error("object '%s' property '%s' not found", arg1, arg2);
			return 0;
		}

		/* assignment, if any */
		if ( value && !object_set_value_by_name(obj,arg2,value) )
		{
			output_error("cannot set object '%s' property '%s' to '%s'", arg1, arg2, value);
			return 0;
		}

		/* post the response */
		http_format(http,"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<property>\n");
		http_format(http,"\t<object>%s</object>\n", arg1);
		http_format(http,"\t<name>%s</name>\n", arg2);
		http_format(http,"\t<value>%s</value>\n", http_unquote(buffer));
		/* TODO add property type info */
		http_format(http,"</property>\n");
		http_type(http,"text/xml");
		return 1;

	default:
		return 0;
	}
	return 0;
}
예제 #5
0
/** Process an incoming request
	@returns nothing
 **/
void http_response(SOCKET fd)
{
	HTTP *http = http_create(fd);
	size_t len;
	int content_length = 0;
	char *user_agent = NULL;
	char *host = NULL;
	int keep_alive = 0;
	char *connection = NULL;
	char *accept = NULL;
	struct s_map {
		char *name;
		enum {INTEGER,STRING} type;
		void *value;
		size_t sz;
	} map[] = {
		{"Content-Length", INTEGER, (void*)&content_length, 0},
		{"Host", STRING, (void*)&host, 0},
		{"Keep-Alive", INTEGER, (void*)&keep_alive, 0},
		{"Connection", STRING, (void*)&connection, 0},
		{"Accept", STRING, (void*)&accept, 0},
	};

	while ( (int)(len=recv_data(fd,http->query,sizeof(http->query)))>0 )
	{
		/* first term is always the request */
		char *request = http->query;
		char method[32];
		char uri[1024];
		char version[32];
		char *p = strchr(http->query,'\r');
		int v;
		
		/* initialize the response */
		http_reset(http);

		/* read the request string */
		if (sscanf(request,"%s %s %s",method,uri,version)!=3)
		{
			http_status(http,HTTP_BADREQUEST);
			http_format(http,HTTP_BADREQUEST);
			http_type(http,"text/html");
			http_send(http);
			break;
		}

		/* read the rest of the header */
		while (p!=NULL && (p=strchr(p,'\r'))!=NULL) 
		{
 			*p = '\0';
			p+=2;
			for ( v=0 ; v<sizeof(map)/sizeof(map[0]) ; v++ )
			{
				if (map[v].sz==0) map[v].sz = strlen(map[v].name);
				if (strnicmp(map[v].name,p,map[v].sz)==0 && strncmp(p+map[v].sz,": ",2)==0)
				{
					if (map[v].type==INTEGER) { *(int*)(map[v].value) = atoi(p+map[v].sz+2); break; }
					else if (map[v].type==STRING) { *(char**)map[v].value = p+map[v].sz+2; break; }
				}
			}
		}
		output_verbose("%s (host='%s', len=%d)",http->query,host?host:"???",content_length);

		/* reject anything but a GET */
		if (stricmp(method,"GET")!=0)
		{
			http_status(http,HTTP_METHODNOTALLOWED);
			http_format(http,HTTP_METHODNOTALLOWED);
			http_type(http,"text/html");
			/* technically, we should add an Allow entry to the response header */
			http_send(http);
			break;
		}

		/* handle request */
		if ( strcmp(uri,"/favicon.ico")==0 )
		{
			if ( http_favicon(http) )
				http_status(http,HTTP_OK);
			else
				http_status(http,HTTP_NOTFOUND);
			http_send(http);
		}
		else {
			static struct s_map {
				char *path;
				int (*request)(HTTP*,char*);
				char *success;
				char *failure;
			} map[] = {
				/* this is the map of recognize request types */
				{"/xml/",		http_xml_request,		HTTP_OK, HTTP_NOTFOUND},
				{"/gui/",		http_gui_request,		HTTP_OK, HTTP_NOTFOUND},
				{"/output/",	http_output_request,	HTTP_OK, HTTP_NOTFOUND},
				{"/action/",	http_action_request,	HTTP_ACCEPTED,HTTP_NOTFOUND},
				{"/rt/",		http_get_rt,			HTTP_OK, HTTP_NOTFOUND},
				{"/perl/",		http_run_perl,			HTTP_OK, HTTP_NOTFOUND},
				{"/gnuplot/",	http_run_gnuplot,		HTTP_OK, HTTP_NOTFOUND},
				{"/java/",		http_run_java,			HTTP_OK, HTTP_NOTFOUND},
				{"/python/",	http_run_python,		HTTP_OK, HTTP_NOTFOUND},
				{"/r/",			http_run_r,				HTTP_OK, HTTP_NOTFOUND},
				{"/scilab/",	http_run_scilab,		HTTP_OK, HTTP_NOTFOUND},
				{"/octave/",	http_run_octave,		HTTP_OK, HTTP_NOTFOUND},
			};
			int n;
			for ( n=0 ; n<sizeof(map)/sizeof(map[0]) ; n++ )
			{
				size_t len = strlen(map[n].path);
				if (strncmp(uri,map[n].path,len)==0)
				{
					if ( map[n].request(http,uri+len) )
						http_status(http,map[n].success);
					else
						http_status(http,map[n].failure);
					http_send(http);
					goto Next;
				}
			}
		}
		/* deprecated XML usage */
		if (strncmp(uri,"/",1)==0 )
		{
			if ( http_xml_request(http,uri+1) )
			{	
				output_warning("deprecate XML usage in request '%s'", uri);
				http_status(http,HTTP_OK);
			}
			else
				http_status(http,HTTP_NOTFOUND);
			http_send(http);
		}
		else 
		{
			http_status(http,HTTP_NOTFOUND);
			http_format(http,HTTP_NOTFOUND);
			http_type(http,"text/html");
			http_send(http);
		}

		/* keep-alive not desired*/
Next:
		if (connection && stricmp(connection,"close")==0)
			break;
	}
	http_close(http);
	output_verbose("socket %d closed",http->s);
}
예제 #6
0
/*
 * Send a HTTP response.
 */
bool http_send_response(socket_t s, unsigned http_code,
    http_buffer_t content, const struct http_request_s *request)
{
    const char *http_response_header;
    switch (http_code)
    {
        case 200:
            http_response_header = "HTTP/1.1 200 OK";
            break;
        case 404:
            http_response_header = "HTTP/1.1 404 Not Found";
            break;
        case 500:
            http_response_header = "HTTP/1.1 500 Internal Server Error";
            break;
        default:
            return false;
    }
    const char *http_content_type;
    int type = http_type(request->name);
    switch (type)
    {
        default:
        case HTTP_TYPE_HTML:
            http_content_type = "text/html";
            break;
        case HTTP_TYPE_CSS:
            http_content_type = "text/css";
            break;
        case HTTP_TYPE_JAVASCRIPT:
            http_content_type = "text/javascript";
            break;
        case HTTP_TYPE_TEXT:
            http_content_type = "text/plain";
            break;
        case HTTP_TYPE_SVG:
            http_content_type = "image/svg+xml";
            break;
    }
    http_buffer_t buff;
    if (type == HTTP_TYPE_HTML || type == HTTP_TYPE_JAVASCRIPT)
    {
        buff = http_buffer_open();
        http_expand_content(content, request, buff);
    }
    else
    {
        buff = content;
    }
    const char *http_header_format =
        "%s\r\n"
        "Content-Length: %d\r\n"
        "Connection: close\r\n"
        "Content-Type: %s\r\n"
        "Cache-Control: no-cache, must-revalidate\r\n"
        "Server: " PROGRAM_NAME_LONG "\r\n"
        "\r\n";
    size_t http_body_length = buff->put_pos;
    size_t http_header_length = snprintf(NULL, 0, http_header_format,
        http_response_header, http_body_length, http_content_type);
    size_t http_response_length = http_header_length + http_body_length;
    char *http_response = (char *)malloc(http_response_length);
    if (http_response == NULL)
    {
        error("unable to allocate " SIZE_T_FMT " bytes for HTTP response "
            "buffer", http_response_length);
    }
    snprintf(http_response, http_response_length, http_header_format,
        http_response_header, http_body_length, http_content_type);
    memmove(http_response + http_header_length, buff->buff, http_body_length);
    if (buff != content)
    {
        http_buffer_close(buff);
    }
    bool ret_val = true;
    if (send(s, http_response, http_response_length, 0)
        != http_response_length)
    {
        warning("unable to send HTTP %u response of size " SIZE_T_FMT " bytes",
            http_code, http_response_length);
        ret_val = false;
    }
    free(http_response);
    return ret_val;
}
예제 #7
0
void http_response(SOCKET fd)
{
	HTTP *http = http_create(fd);
	size_t len;
	int content_length = 0;
	char *user_agent = NULL;
	char *host = NULL;
	int keep_alive = 0;
	char *connection = NULL;
	char *accept = NULL;
	struct s_map {
		char *name;
		enum {INTEGER,STRING} type;
		void *value;
		int sz;
	} map[] = {
		{"Content-Length", INTEGER, (void*)&content_length, 0},
		{"Host", STRING, (void*)&host, 0},
		{"Keep-Alive", INTEGER, (void*)&keep_alive, 0},
		{"Connection", STRING, (void*)&connection, 0},
		{"Accept", STRING, (void*)&accept, 0},
	};

	while ( (int)(len=recv_data(fd,http->query,sizeof(http->query)))>0 )
	{
		/* first term is always the request */
		char *request = http->query;
		char method[32];
		char uri[1024];
		char version[32];
		char *p = strchr(http->query,'\r');
		int v;

		/* read the request string */
		if (sscanf(request,"%s %s %s",method,uri,version)!=3)
		{
			http_status(http,HTTP_BADREQUEST);
			http_format(http,HTTP_BADREQUEST);
			http_type(http,"text/html");
			http_send(http);
			break;
		}

		/* read the rest of the header */
		while (p!=NULL && (p=strchr(p,'\r'))!=NULL) 
		{
 			*p = '\0';
			p+=2;
			for ( v=0 ; v<sizeof(map)/sizeof(map[0]) ; v++ )
			{
				if (map[v].sz==0) map[v].sz = strlen(map[v].name);
				if (strnicmp(map[v].name,p,map[v].sz)==0 && strncmp(p+map[v].sz,": ",2)==0)
				{
					if (map[v].type==INTEGER) { *(int*)(map[v].value) = atoi(p+map[v].sz+2); break; }
					else if (map[v].type==STRING) { *(char**)map[v].value = p+map[v].sz+2; break; }
				}
			}
		}
		output_verbose("%s (host='%s', len=%d)",http->query,host?host:"???",content_length);

		/* reject anything but a GET */
		if (stricmp(method,"GET")!=0)
		{
			http_status(http,HTTP_METHODNOTALLOWED);
			http_format(http,HTTP_METHODNOTALLOWED);
			http_type(http,"text/html");
			/* technically, we should add an Allow entry to the response header */
			http_send(http);
			break;
		}

		/* handle request */
		if (strncmp(uri,"/gui/",5)==0 )
		{
			if ( http_gui_request(http,uri+5) )
				http_status(http,HTTP_OK);
			else
				http_status(http,HTTP_NOTFOUND);
			http_send(http);
		}
		else if (strncmp(uri,"/output/",8)==0 )
		{
			if ( http_output_request(http,uri+8) )
				http_status(http,HTTP_OK);
			else
				http_status(http,HTTP_NOTFOUND);
			http_send(http);
		}
		else if (strncmp(uri,"/action/",8)==0) 
		{
			if ( http_action_request(http,uri+8) )
				http_status(http,HTTP_ACCEPTED);
			else
				http_status(http,HTTP_NOTFOUND);
			http_send(http);
		}
		else if ( strcmp(uri,"/favicon.ico")==0 )
		{
			if ( http_favicon(http) )
				http_status(http,HTTP_OK);
			else
				http_status(http,HTTP_NOTFOUND);
			http_send(http);
		}
		else if (strncmp(uri,"/",1)==0 )
		{
			if ( http_xml_request(http,uri+1) )
				http_status(http,HTTP_OK);
			else
				http_status(http,HTTP_NOTFOUND);
			http_send(http);
		}
		else 
		{
			http_status(http,HTTP_NOTFOUND);
			http_format(http,HTTP_NOTFOUND);
			http_type(http,"text/html");
			http_send(http);
		}

		/* keep-alive not desired*/
		if (connection && stricmp(connection,"close")==0)
			break;
	}
	http_close(http);
	output_verbose("socket %d closed",http->s);
}