Exemple #1
0
onion_connection_status upload_file(upload_file_data *data, onion_request *req, onion_response *res){
	if (onion_request_get_flags(req)&OR_POST){
		const char *name=onion_request_get_post(req,"file");
		const char *filename=onion_request_get_file(req,"file");
		
		if (name && filename){
			char finalname[1024];
			snprintf(finalname,sizeof(finalname),"%s/%s",data->abspath,name);
			ONION_DEBUG("Copying from %s to %s",filename,finalname);

			unlink(finalname); // Just try to unlink it, if fail, sure its because it does not exist.
			int src=open(filename,O_RDONLY);
			int dst=open(finalname, O_WRONLY|O_CREAT, 0666);
			if (!src || !dst){
				ONION_ERROR("Could not open src or dst file (%d %d)",src,dst);
				return OCS_INTERNAL_ERROR;
			}
			ssize_t r,w;
			char buffer[1024*4];
			while ( (r=read(src,buffer,sizeof(buffer))) > 0){
				w=write(dst,buffer,r);
				if (w!=r){
					ONION_ERROR("Error writing file");
					break;
				}
			}
			close(src);
			close(dst);
		}
	}
	return 0; // I just ignore the request, but process over the FILE data
}
Exemple #2
0
onion_connection_status method(void *ignore, onion_request *req, onion_response *res){
	if (onion_response_write_headers(res)==OR_SKIP_CONTENT) // Head
		return OCS_PROCESSED;
	
	onion_response_write0(res, "<html><body>\n<h1>Petition resume</h1>\n");
	int flags=onion_request_get_flags(req);
	if (flags&OR_GET)
		onion_response_write0(res,"<h2>GET");
	else if (flags&OR_POST)
		onion_response_write0(res,"<h2>POST");
	else 
		onion_response_write0(res,"<h2>UNKNOWN");
	
	onion_response_printf(res," %s</h2>\n<ul>",onion_request_get_path(req));

	const onion_dict *get=onion_request_get_query_dict(req);
	const onion_dict *post=onion_request_get_post_dict(req);
	const onion_dict *headers=onion_request_get_header_dict(req);
	
	onion_response_printf(res,"<li>Header %d elements<ul>",onion_dict_count(headers));
	if (headers) onion_dict_preorder(headers, print_dict_element, res);
	onion_response_printf(res,"</ul></li>\n");

	onion_response_printf(res,"<li>GET %d elements<ul>",onion_dict_count(get));
	if (get) onion_dict_preorder(get, print_dict_element, res);
	onion_response_printf(res,"</ul></li>\n");

	onion_response_printf(res,"<li>POST %d elements<ul>",onion_dict_count(post));
	if (post) onion_dict_preorder(post, print_dict_element, res);
	onion_response_printf(res,"</ul></li>\n");

	onion_response_write0(res,"<p>\n");
	onion_response_write0(res,"<form method=\"GET\">"
														"<input type=\"text\" name=\"test\">"
														"<input type=\"submit\" name=\"submit\" value=\"GET\">"
														"</form><p>\n");
	onion_response_write0(res,"<form method=\"POST\" enctype=\"application/x-www-form-urlencoded\">"
														"<textarea name=\"text\"></textarea>"
														"<input type=\"text\" name=\"test\">"
														"<input type=\"submit\" name=\"submit\"  value=\"POST urlencoded\">"
														"</form>"
														"<p>\n");
	onion_response_write0(res,"<form method=\"POST\" enctype=\"multipart/form-data\">"
														"<input type=\"file\" name=\"file\">"
														"<textarea name=\"text\"></textarea>"
														"<input type=\"text\" name=\"test\">"
														"<input type=\"submit\" name=\"submit\" value=\"POST multipart\">"
														"</form>"
														"<p>\n");
	
	onion_response_write0(res,"</body></html>");
	
	return OCS_PROCESSED;
}
Exemple #3
0
/**
 * @short Handler that just echoes all data, writing what was a header, what the method...
 */
onion_connection_status allinfo_handler(void *data, onion_request *req){
	onion_response *res=onion_response_new(req);
	onion_response_write_headers(res);
	
	int f=onion_request_get_flags(req);
	onion_response_printf(res, "Method: %s\n",(f&OR_GET) ? "GET" : (f&OR_HEAD) ? "HEAD" : "POST");
	onion_response_printf(res, "Path: %s\n",onion_request_get_path(req));
	onion_response_printf(res, "Version: %s\n",onion_request_get_flags(req)&OR_HTTP11 ? "HTTP/1.1" : "HTTP/1.0");

	allinfo_dict_print_t aid;
	aid.res=res;
	aid.part="Query";
	onion_dict_preorder(onion_request_get_query_dict(req),allinfo_query, &aid);
	aid.part="Header";
	onion_dict_preorder(onion_request_get_header_dict(req),allinfo_query, &aid);
	aid.part="POST";
	onion_dict_preorder(onion_request_get_post_dict(req),allinfo_query, &aid);
	aid.part="FILE";
	onion_dict_preorder(onion_request_get_file_dict(req),allinfo_query, &aid);
	
	return onion_response_free(res);;
}
Exemple #4
0
/**
 * @short Serves a directory listing.
 * 
 * It checks if the given request is a directory listing and processes it, or fallbacks to the
 * next handler.
 */
int fileserver_page(const char *basepath, onion_request *req, onion_response *res){
	if ((onion_request_get_flags(req)&OR_METHODS) == OR_GET){ // only get.
		const char *path=onion_request_get_path(req); // Try to get the real path, and check if its a dir
		
		char dirname[256];
		snprintf(dirname, sizeof(dirname), "%s/%s", basepath, onion_request_get_path(req));
		char *realp=realpath(dirname, NULL);
		if (!realp)
			return OCS_INTERNAL_ERROR;
		
		DIR *dir=opendir(realp);
		if (dir){ // its a dir, fill the dictionary.
			onion_dict *d=onion_dict_new();
			onion_dict_add(d, "dirname", path, 0);
			if (path[0]!='\0' && path[1]!='\0')
				onion_dict_add(d, "go_up", "true", 0);
			onion_dict *files=onion_dict_new();
			onion_dict_add(d, "files", files, OD_DICT|OD_FREE_VALUE);
			
			struct dirent *de;
			while ( (de=readdir(dir)) ){ // Fill one files.[filename] per file.
				onion_dict *file=onion_dict_new();
				onion_dict_add(files, de->d_name, file, OD_DUP_KEY|OD_DICT|OD_FREE_VALUE);
				
				onion_dict_add(file, "name", de->d_name, OD_DUP_VALUE);

				char tmp[256];
				snprintf(tmp, sizeof(tmp), "%s/%s", realp, de->d_name);
				struct stat st;
				stat(tmp, &st);
			
				snprintf(tmp, sizeof(tmp), "%d", (int)st.st_size);
				onion_dict_add(file, "size", tmp, OD_DUP_VALUE);
				
				snprintf(tmp, sizeof(tmp), "%d", st.st_uid);
				onion_dict_add(file, "owner", tmp, OD_DUP_VALUE);
				
				if (S_ISDIR(st.st_mode))
					onion_dict_add(file, "type", "dir", 0);
				else
					onion_dict_add(file, "type", "file", 0);
			}
			closedir(dir);
			free(realp);
			
			return fileserver_html_template(d, req, res);
		}
		free(realp);
	}
	return OCS_NOT_PROCESSED;
}
//HTTP handler to forward http requests
int forward(void *p, onion_request *req, onion_response *res){

	if (onion_request_get_flags(req)&OR_GET){
		printf("We got a GET. WOHOOOOOO!!!\n")
	}

	//Set header and type
	onion_response_set_header(res, "HTTP-Translator", "Forward that data");
	onion_response_set_header(res, "Content-Type", "text/plain");

	//Set example message
	onion_response_write0(res, "First try");

	//Tell if everything worked properly
	return OCS_PROCESSED;
}
Exemple #6
0
onion_connection_status post_json_check(json_response *post, onion_request *req, onion_response *res){
	post->processed=1;
	
	FAIL_IF_NOT_EQUAL_INT(onion_request_get_flags(req)&OR_METHODS, OR_POST);
	FAIL_IF_NOT_EQUAL_STR(onion_request_get_header(req, "Content-Type"),"application/json");
	const onion_block *data=onion_request_get_data(req);
	FAIL_IF_EQUAL(data, NULL);
	if (!data)
		return OCS_INTERNAL_ERROR;
	
	FAIL_IF_NOT_EQUAL_INT(onion_block_size(data), sizeof(JSON_EXAMPLE));
	FAIL_IF_NOT_EQUAL_INT(memcmp(onion_block_data(data), JSON_EXAMPLE, sizeof(JSON_EXAMPLE)), 0);
	
	post->processed=2;
	
	return OCS_PROCESSED;
}
Exemple #7
0
/**
 * @short Main webdav handler, just redirects to the proper handler depending on headers and method
 */
onion_connection_status onion_webdav_handler(onion_webdav *wd, onion_request *req, onion_response *res){
	onion_response_set_header(res, "Dav", "1,2");
	onion_response_set_header(res, "MS-Author-Via", "DAV");
	
#ifdef __DEBUG__
	const onion_block *data=onion_request_get_data(req);
	if (data){
		ONION_DEBUG0("Have data!\n %s", onion_block_data(data));
	}
#endif

	
	char filename[512];
	snprintf(filename, sizeof(filename), "%s/%s", wd->path, onion_request_get_path(req));
	
	ONION_DEBUG("Check %s and %s", wd->path, filename);
	if (wd->check_permissions(wd->path, filename, req)!=0){
		return onion_shortcut_response("Forbidden", HTTP_FORBIDDEN, req, res);
	}

	
	switch (onion_request_get_flags(req)&OR_METHODS){
		case OR_GET:
		case OR_HEAD:
			return onion_webdav_get(filename, wd, req, res);
		case OR_OPTIONS:
			return onion_webdav_options(filename, wd, req, res);
		case OR_PROPFIND:
			return onion_webdav_propfind(filename, wd, req, res);
		case OR_PUT:
			return onion_webdav_put(filename, wd, req, res);
		case OR_DELETE:
			return onion_webdav_delete(filename, wd, req, res);
		case OR_MOVE:
			return onion_webdav_move(filename, wd, req, res);
		case OR_MKCOL:
			return onion_webdav_mkcol(filename, wd, req, res);
		case OR_PROPPATCH:
			return onion_webdav_proppatch(filename, wd, req, res);
	}
	
	onion_response_set_code(res, HTTP_NOT_IMPLEMENTED);
	onion_response_write0(res, "<h1>Work in progress...</h1>\n");
	
	return OCS_PROCESSED;
}
Exemple #8
0
onion_connection_status check_answer(void *privdata, onion_request *req, onion_response *res)
{
	trivia_question const* const q = privdata;
	if (onion_request_get_flags(req)&OR_HEAD){
		onion_response_write_headers(res);
		return OCS_PROCESSED;
	}
	const char *answer = onion_request_get_post(req,"answer");
	const char *uri;
	if(strcmp_ignoring_case_and_whitespace(q->correct_answer, answer) == 0) {
		lamp->green = 65535;
		uri = q->correct_uri;
	} else {
		lamp->red = 65535;
		uri = q->again_uri;
	}
	return onion_shortcut_response_extra_headers("<h1>302 - Moved</h1>", HTTP_REDIRECT, req, res, "Location", uri, NULL );
}
/**
 * @short This shortcut returns the given file contents. 
 * 
 * It sets all the compilant headers (TODO), cache and so on.
 * 
 * This is the recomended way to send static files; it even can use sendfile Linux call 
 * if suitable (TODO).
 * 
 * It does no security checks, so caller must be security aware.
 */
onion_connection_status onion_shortcut_response_file(const char *filename, onion_request *request, onion_response *res){
	int fd=open(filename,O_RDONLY|O_CLOEXEC);
	
	if (fd<0)
		return OCS_NOT_PROCESSED;

	if(O_CLOEXEC == 0) { // Good compiler know how to cut this out
		int flags=fcntl(fd, F_GETFD);
		if (flags==-1){
			ONION_ERROR("Retrieving flags from file descriptor");
		}
		flags|=FD_CLOEXEC;
		if (fcntl(fd, F_SETFD, flags)==-1){
			ONION_ERROR("Setting O_CLOEXEC to file descriptor");
		}
	}
	
	struct stat st;
	if (stat(filename, &st)!=0){
		ONION_WARNING("File does not exist: %s",filename);
		close(fd);
		return OCS_NOT_PROCESSED;
	}
	
	if (S_ISDIR(st.st_mode)){
		close(fd);
		return OCS_NOT_PROCESSED;
	}
	
	size_t length=st.st_size;
	
	char etag[64];
	onion_shortcut_etag(&st, etag);
		
	const char *range=onion_request_get_header(request, "Range");
	if (range){
		strncat(etag,range,sizeof(etag)-1);
	}
	onion_response_set_header(res, "Etag", etag);
	
	if (range && strncmp(range,"bytes=",6)==0){
		onion_response_set_code(res, HTTP_PARTIAL_CONTENT);
		//ONION_DEBUG("Need just a range: %s",range);
		char tmp[1024];
		strncpy(tmp, range+6, 1024);
		char *start=tmp;
		char *end=tmp;
		while (*end!='-' && *end) end++;
		if (*end=='-'){
			*end='\0';
			end++;
			
			//ONION_DEBUG("Start %s, end %s",start,end);
			size_t ends, starts;
			if (*end)
				ends=atol(end);
			else
				ends=length;
			starts=atol(start);
			length=ends-starts+1;
			lseek(fd, starts, SEEK_SET);
			snprintf(tmp,sizeof(tmp),"bytes %d-%d/%d",(unsigned int)starts, (unsigned int)ends, (unsigned int)st.st_size);
			//onion_response_set_header(res, "Accept-Ranges","bytes");
			onion_response_set_header(res, "Content-Range",tmp);
		}
	}
	
	onion_response_set_length(res, length);
	onion_response_set_header(res, "Content-Type", onion_mime_get(filename) );
	ONION_DEBUG("Mime type is %s",onion_mime_get(filename));

  ONION_DEBUG0("Etag %s", etag);
  const char *prev_etag=onion_request_get_header(request, "If-None-Match");
  if (prev_etag && (strcmp(prev_etag, etag)==0)){
    ONION_DEBUG0("Not modified");
    onion_response_set_length(res, 0);
    onion_response_set_code(res, HTTP_NOT_MODIFIED);
    onion_response_write_headers(res);
    close(fd);
    return OCS_PROCESSED;
  }
	onion_response_write_headers(res);
	if ((onion_request_get_flags(request)&OR_HEAD) == OR_HEAD){ // Just head.
		length=0;
	}
	
	if (length){
#ifdef USE_SENDFILE
		if (request->connection.listen_point->write==(void*)onion_http_write){ // Lets have a house party! I can use sendfile!
			onion_response_write(res,NULL,0);
			ONION_DEBUG("Using sendfile");
			int r=sendfile(request->connection.fd, fd, NULL, length);
			ONION_DEBUG("Wrote %d, should be %d (%s)", r, length, r==length ? "ok" : "nok");
			if (r!=length || r<0){
				ONION_ERROR("Could not send all file (%s)", strerror(errno));
				close(fd);
				return OCS_INTERNAL_ERROR;
			}
			res->sent_bytes+=length;
			res->sent_bytes_total+=length;
		}
		else
#endif
		{ // Ok, no I cant, do it as always.
			int r=0,w;
			size_t tr=0;
			char tmp[4046];
			if (length>sizeof(tmp)){
				size_t max=length-sizeof(tmp);
				while( tr<max ){
					r=read(fd,tmp,sizeof(tmp));
					tr+=r;
					if (r<0)
						break;
					w=onion_response_write(res, tmp, r);
					if (w!=r){
						ONION_ERROR("Wrote less than read: write %d, read %d. Quite probably closed connection.",w,r);
						break;
					}
				}
			}
			if (sizeof(tmp) >= (length-tr)){
				r=read(fd, tmp, length-tr);
				w=onion_response_write(res, tmp, r);
				if (w!=r){
					ONION_ERROR("Wrote less than read: write %d, read %d. Quite probably closed connection.",w,r);
				}
			}
		}
	}
	close(fd);
	return OCS_PROCESSED;
}