Exemplo n.º 1
0
/*
 Return raw file if found. Security risk?! Check of filename/path required?!
*/
int search_file(onion_dict *context, onion_request *req, onion_response *res){
	//const char* path = onion_request_get_path(req);//empty?!
	const char* path = onion_request_get_fullpath(req);
	printf("Request of %s %i.\n",path, strlen(path));
	char filename[strlen(path)+8];
	//sprintf(filename,"./%s",path);
	sprintf(filename,"./html/%s",path);

		//read file 
	if( FILE *f=fopen(filename,"rb") ){
		fseek(f,0,SEEK_END);
		long len=ftell(f);
		fseek(f,0,SEEK_SET);
		char *data=(char*)malloc(len+1);
		fread(data,1,len,f);
		fclose(f);

		if (context) onion_dict_add(context, "LANG", onion_request_get_language_code(req), OD_FREE_VALUE);
		onion_response_set_length(res, len);
		onion_response_write(res, data, len); 
		if (context) onion_dict_free(context);

		free(data);
	}else{
		onion_response_set_length(res, 24);
		onion_response_write(res, "<h1>File not found</h1>", 24); 
	}
	return OCS_PROCESSED;
}
Exemplo n.º 2
0
/*
 Check post values and then return template of index.html.
 (Or use *p for other callbacks (not implemented))
*/
int checkFormularValues(void *p, onion_request *req, onion_response *res){
	int ok = ((OnionServer*)p)->updateSetting(req,res);
	if( ok != 0){
		onion_response_set_length(res, 6);
		onion_response_write(res, "reload", 6); 
	}else{
		onion_response_set_length(res, 2);
		onion_response_write(res, "Ok", 2); 
	}
	return OCS_PROCESSED;
}
Exemplo n.º 3
0
void t02_full_cycle_http10(){
	INIT_LOCAL();
	
	onion *server=onion_new(0);
	onion_add_listen_point(server,NULL,NULL,onion_buffer_listen_point_new());
	onion_request *request;
	char buffer[4096];
	memset(buffer,0,sizeof(buffer));
	
	request=onion_request_new(server->listen_points[0]);
	
	onion_response *response=onion_response_new(request);
	
	onion_response_set_length(response, 30);
	FAIL_IF_NOT_EQUAL(response->length,30);
	onion_response_write_headers(response);
	
	onion_response_write0(response,"123456789012345678901234567890");
	onion_response_flush(response);
	FAIL_IF_NOT_EQUAL(response->sent_bytes,30);
	
	onion_response_free(response);
	strncpy(buffer,onion_buffer_listen_point_get_buffer_data(request),sizeof(buffer));
	onion_request_free(request);
	onion_free(server);
	
	FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.0 200 OK\r\n");
	FAIL_IF_NOT_STRSTR(buffer, "Connection: Keep-Alive\r\n");
	FAIL_IF_NOT_STRSTR(buffer, "Content-Length: 30\r\n");
	FAIL_IF_NOT_STRSTR(buffer, "Server: libonion");
	FAIL_IF_NOT_STRSTR(buffer, "coralbits");
	FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\n123456789012345678901234567890");
	
	END_LOCAL();
}
Exemplo n.º 4
0
/**
 * @short Tryes to handle the petition with that handler.
 * @memberof onion_handler_t
 *
 * It needs the handler to handle, the request and the response.
 *
 * It checks this parser, and siblings.
 * 
 * @returns If can not, returns OCS_NOT_PROCESSED (0), else the onion_connection_status. (normally OCS_PROCESSED)
 */
onion_connection_status onion_handler_handle(onion_handler *handler, onion_request *request, onion_response *response){
	onion_connection_status res;
	while (handler){
		if (handler->handler){
#ifdef __DEBUG0__
			char **bs=backtrace_symbols((void * const *)&handler->handler, 1);
			ONION_DEBUG0("Calling handler: %s",bs[0]);
			/* backtrace_symbols is explicitly documented
			   to malloc. We need to call the system free
			   routine, not our onion_low_free ! */
			onion_low_free(bs); /* Can't be onion_low_free.... */
#endif
			res=handler->handler(handler->priv_data, request, response);
			ONION_DEBUG0("Result: %d",res);
			if (res){
				// write pending data.
				if (!(response->flags&OR_HEADER_SENT) && response->buffer_pos<sizeof(response->buffer))
					onion_response_set_length(response, response->buffer_pos);
				onion_response_flush(response);
				if (res==OCS_WEBSOCKET){
					if (request->websocket)
						return onion_websocket_call(request->websocket);
					else{
						ONION_ERROR("Handler did set the OCS_WEBSOCKET, but did not initialize the websocket on this request.");
						return OCS_INTERNAL_ERROR;
					}
				}
				return res;
			}
		}
		handler=handler->next;
	}
	return OCS_NOT_PROCESSED;
}
Exemplo n.º 5
0
/**
 * @short Returns known options.
 * 
 * Just known options, no more. I think many clients ignore this. (without PUT, gnome's file manager was trying).
 */
onion_connection_status onion_webdav_options(const char *filename, onion_webdav *wd, onion_request *req, onion_response *res){
	onion_response_set_header(res, "Allow", "OPTIONS,GET,HEAD,PUT,PROPFIND");
	onion_response_set_header(res, "Content-Type", "httpd/unix-directory");
	
	onion_response_set_length(res, 0);
	
	onion_response_write_headers(res);
	
	return OCS_PROCESSED;
}
Exemplo n.º 6
0
/**
 * @short Performs the real request: set the code and write data
 */
int onion_handler_static_handler(onion_handler_static_data *d, onion_request *request, onion_response *res){
	int length=strlen(d->data);
	onion_response_set_length(res, length);
	onion_response_set_code(res, d->code);
	
	onion_response_write_headers(res);
	//fprintf(stderr,"Write %d bytes\n",length);
	onion_response_write(res, d->data, length);

	return OCS_PROCESSED;
}
Exemplo n.º 7
0
int onion_handler_opack_handler(onion_handler_opack_data *d, onion_request *request, onion_response *res){
	if (strcmp(d->path, onion_request_get_path(request))!=0)
		return 0;
		
	if (d->length)
		onion_response_set_length(res, d->length);
	onion_response_write_headers(res);

	d->render(res);
	
	return OCS_PROCESSED;
}
Exemplo n.º 8
0
int onion_handler_auth_pam_handler(onion_handler_auth_pam_data *d, onion_request *request, onion_response *res){
	/// Use session to know if already logged in, so do not mess with PAM so often.
	if (onion_request_get_session(request, "pam_logged_in"))
		return onion_handler_handle(d->inside, request, res);
	
	const char *o=onion_request_get_header(request, "Authorization");
	char *auth=NULL;
	char *username=NULL;
	char *passwd=NULL;
	if (o && strncmp(o,"Basic",5)==0){
		//fprintf(stderr,"auth: '%s'\n",&o[6]);
		auth=onion_base64_decode(&o[6], NULL);
		username=auth;
		int i=0;
		while (auth[i]!='\0' && auth[i]!=':') i++;
		if (auth[i]==':'){
			auth[i]='\0'; // so i have user ready
			passwd=&auth[i+1];
		}
		else
			passwd=NULL;
	}
	
	// I have my data, try to authorize
	if (username && passwd){
		int ok=authorize(d->pamname, username, passwd);
		
		if (ok){ // I save the username at the session, so it can be accessed later.
			onion_dict *session=onion_request_get_session_dict(request);
			onion_dict_lock_write(session);
			onion_dict_add(session, "username", username, OD_REPLACE|OD_DUP_VALUE);
			onion_dict_add(session, "pam_logged_in", username, OD_REPLACE|OD_DUP_VALUE);
			onion_dict_unlock(session);
			
			free(auth);
			return onion_handler_handle(d->inside, request, res);
		}
	}
	if (auth)
		free(auth);

	
	// Not authorized. Ask for it.
	char temp[256];
	sprintf(temp, "Basic realm=\"%s\"",d->realm);
	onion_response_set_header(res, "WWW-Authenticate",temp);
	onion_response_set_code(res, HTTP_UNAUTHORIZED);
	onion_response_set_length(res,sizeof(RESPONSE_UNAUTHORIZED));
	
	onion_response_write(res,RESPONSE_UNAUTHORIZED,sizeof(RESPONSE_UNAUTHORIZED));
	return OCS_PROCESSED;
}
Exemplo n.º 9
0
/**
 * @short Handles a propfind
 * 
 * @param path the shared path.
 */
onion_connection_status onion_webdav_propfind(const char *filename, onion_webdav *wd, onion_request* req, onion_response* res){
	// Prepare the basepath, necesary for props.
	char *basepath=NULL;
	int pathlen=0;
	const char *current_path=onion_request_get_path(req);
	const char *fullpath=onion_request_get_fullpath(req);
	pathlen=(current_path-fullpath);
	basepath=alloca(pathlen+1);
	memcpy(basepath, fullpath, pathlen+1);
	ONION_DEBUG0("Pathbase initial <%s> %d", basepath, pathlen); 
	while(basepath[pathlen]=='/' && pathlen>0)
		pathlen--;
	basepath[pathlen+1]=0;
				 
	ONION_DEBUG0("PROPFIND; pathbase %s", basepath);
	int depth;
	{
		const char *depths=onion_request_get_header(req, "Depth");
		if (!depths){
			ONION_ERROR("Missing Depth header on webdav request");
			return OCS_INTERNAL_ERROR;
		}
		if (strcmp(depths,"infinity")==0){
			ONION_ERROR("Infinity depth not supported yet.");
			return OCS_INTERNAL_ERROR;
		}
		depth=atoi(depths);
	}

	int props=onion_webdav_parse_propfind(onion_request_get_data(req));
	ONION_DEBUG("Asking for props %08X, depth %d", props, depth);
	
	onion_block *block=onion_webdav_write_propfind(basepath, filename, onion_request_get_path(req), depth, props);
	
	if (!block) // No block, resource does not exist
		return onion_shortcut_response("Not found", HTTP_NOT_FOUND, req, res);
		
	ONION_DEBUG0("Printing block %s", onion_block_data(block));
	
	onion_response_set_header(res, "Content-Type", "text/xml; charset=\"utf-8\"");
	onion_response_set_length(res, onion_block_size(block));
	onion_response_set_code(res, HTTP_MULTI_STATUS);
	onion_response_write_headers(res);
	onion_response_flush(res);
	
	onion_response_write(res, onion_block_data(block), onion_block_size(block));
	
	onion_block_free(block);
	
	return OCS_PROCESSED;
}
Exemplo n.º 10
0
void t01_create_add_free(){
	INIT_LOCAL();
	
	onion_response *res;
	
	res=onion_response_new(NULL);
	FAIL_IF_NOT_EQUAL(res->code, 200);
	
	FAIL_IF_EQUAL(res,NULL);
	
	onion_response_set_length(res,1024);
	FAIL_IF_NOT_EQUAL_STR(onion_dict_get(res->headers,"Content-Length"),"1024");
	
	onion_response_free(res);
	
	END_LOCAL();
}
Exemplo n.º 11
0
/**
 * @short Frees the memory consumed by this object
 * @memberof onion_response_t
 * @ingroup response
 *
 * This function returns the close status: OR_KEEP_ALIVE or OR_CLOSE_CONNECTION as needed.
 *
 * @returns Whether the connection should be closed or not, or an error status to be handled by server.
 * @see onion_connection_status
 */
onion_connection_status onion_response_free(onion_response * res) {
  // write pending data.
  if (!(res->flags & OR_HEADER_SENT) && res->buffer_pos < sizeof(res->buffer))
    onion_response_set_length(res, res->buffer_pos);

  if (!(res->flags & OR_HEADER_SENT))
    onion_response_write_headers(res);

  onion_response_flush(res);
  onion_request *req = res->request;

  if (res->flags & OR_CHUNKED) {        // Set the chunked data end.
    req->connection.listen_point->write(req, "0\r\n\r\n", 5);
  }

  int r = OCS_CLOSE_CONNECTION;

  // it is a rare ocasion that there is no request, but although unlikely, it may happen
  if (req) {
    // keep alive only on HTTP/1.1.
    ONION_DEBUG0
        ("keep alive [req wants] %d && ([skip] %d || [lenght ok] %d==%d || [chunked] %d)",
         onion_request_keep_alive(req), res->flags & OR_SKIP_CONTENT,
         res->length, res->sent_bytes, res->flags & OR_CHUNKED);
    if (onion_request_keep_alive(req)
        && (res->flags & OR_SKIP_CONTENT || res->length == res->sent_bytes
            || res->flags & OR_CHUNKED)
        )
      r = OCS_KEEP_ALIVE;

    if ((onion_log_flags & OF_NOINFO) != OF_NOINFO)
      // FIXME! This is no proper logging at all. Maybe use a handler.
      ONION_INFO("[%s] \"%s %s\" %d %d (%s)",
                 onion_request_get_client_description(res->request),
                 onion_request_methods[res->request->flags & OR_METHODS],
                 res->request->fullpath, res->code, res->sent_bytes,
                 (r == OCS_KEEP_ALIVE) ? "Keep-Alive" : "Close connection");
  }

  onion_dict_free(res->headers);
  onion_low_free(res);

  return r;
}
Exemplo n.º 12
0
/**
 * @short Shortcut for fast responses, like errors, with extra headers
 * 
 * Prepares a fast response. You pass only the request, the text and the code, and it do the full response
 * object and sends the data.
 * 
 * On this version you also pass a NULL terminated list of headers, in key, value pairs.
 */
onion_connection_status onion_shortcut_response_extra_headers(const char* response, int code, onion_request* req, onion_response *res, ... ){
	unsigned int l=strlen(response);
	const char *key, *value;
	
	onion_response_set_length(res,l);
	onion_response_set_code(res,code);
	
	va_list ap;
	va_start(ap, res);
	while ( (key=va_arg(ap, const char *)) ){
		value=va_arg(ap, const char *);
		if (key && value)
			onion_response_set_header(res, key, value);
		else
			break;
	}
	va_end(ap);

	onion_response_write_headers(res);
	
	onion_response_write(res,response,l);
	return OCS_PROCESSED;
}
Exemplo n.º 13
0
/**
 * @short Default error printer. 
 * @memberof onion_server_t
 * 
 * Ugly errors, that can be reimplemented setting a handler with onion_server_set_internal_error_handler.
 */
static int onion_default_error(void *handler, onion_request *req, onion_response *res){
	const char *msg;
	int l;
	int code;
	switch(req->flags&0x0F000){
		case OR_INTERNAL_ERROR:
			msg=ERROR_500;
			l=sizeof(ERROR_500)-1;
			code=HTTP_INTERNAL_ERROR;
			break;
		case OR_NOT_IMPLEMENTED:
			msg=ERROR_505;
			l=sizeof(ERROR_505)-1;
			code=HTTP_NOT_IMPLEMENTED;
			break;
    case OR_FORBIDDEN:
      msg=ERROR_403;
      l=sizeof(ERROR_403)-1;
      code=HTTP_FORBIDDEN;
      break;
		default:
			msg=ERROR_404;
			l=sizeof(ERROR_404)-1;
			code=HTTP_NOT_FOUND;
			break;
	}
	
	ONION_DEBUG0("Internally managed error: %s, code %d.", msg, code);
	
	onion_response_set_code(res,code);
	onion_response_set_length(res, l);
	onion_response_write_headers(res);
	
	onion_response_write(res,msg,l);
	return OCS_PROCESSED;
}
Exemplo n.º 14
0
/**
 * @short Handles a propfind
 * 
 * @param path the shared path.
 */
onion_connection_status onion_webdav_propfind(const char *filename, onion_webdav *wd, onion_request* req, onion_response* res){
	ONION_DEBUG0("PROPFIND");
	int depth;
	{
		const char *depths=onion_request_get_header(req, "Depth");
		if (!depths){
			ONION_ERROR("Missing Depth header on webdav request");
			return OCS_INTERNAL_ERROR;
		}
		if (strcmp(depths,"infinity")==0){
			ONION_ERROR("Infinity depth not supported yet.");
			return OCS_INTERNAL_ERROR;
		}
		depth=atoi(depths);
	}

	int props=onion_webdav_parse_propfind(onion_request_get_data(req));
	ONION_DEBUG("Asking for props %08X, depth %d", props, depth);
	
	onion_block *block=onion_webdav_write_propfind(filename, onion_request_get_path(req), depth, props);
	
	if (!block) // No block, resource does not exist
		return onion_shortcut_response("Not found", HTTP_NOT_FOUND, req, res);
		
	ONION_DEBUG0("Printing block %s", onion_block_data(block));
	
	onion_response_set_header(res, "Content-Type", "text/xml; charset=\"utf-8\"");
	onion_response_set_length(res, onion_block_size(block));
	onion_response_set_code(res, HTTP_MULTI_STATUS);
	
	onion_response_write(res, onion_block_data(block), onion_block_size(block));
	
	onion_block_free(block);
	
	return OCS_PROCESSED;
}
Exemplo n.º 15
0
onion_connection_status opack_index_html(void *_, onion_request *req, onion_response *res){
  char data[]={
0x3C, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x0A, 0x20, 0x3C, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x3E, 
0x0A, 0x20, 0x20, 0x3C, 0x74, 0x69, 0x74, 0x6C, 0x65, 0x3E, 0x4F, 0x6E, 0x69, 0x6F, 0x6E, 0x20, 
0x54, 0x6F, 0x70, 0x3C, 0x2F, 0x74, 0x69, 0x74, 0x6C, 0x65, 0x3E, 0x0A, 0x20, 0x20, 0x3C, 0x73, 
0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x73, 0x72, 0x63, 0x3D, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3A, 
0x2F, 0x2F, 0x63, 0x6F, 0x64, 0x65, 0x2E, 0x6A, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2E, 0x63, 0x6F, 
0x6D, 0x2F, 0x6A, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2D, 0x31, 0x2E, 0x34, 0x2E, 0x33, 0x2E, 0x6D, 
0x69, 0x6E, 0x2E, 0x6A, 0x73, 0x22, 0x3E, 0x3C, 0x2F, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3E, 
0x0A, 0x3C, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3E, 0x0A, 0x62, 0x6F, 0x64, 0x79, 0x7B, 0x0A, 0x09, 
0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x3A, 0x20, 0x23, 0x66, 0x65, 0x66, 
0x65, 0x66, 0x65, 0x3B, 0x0A, 0x09, 0x66, 0x6F, 0x6E, 0x74, 0x2D, 0x66, 0x61, 0x6D, 0x69, 0x6C, 
0x79, 0x3A, 0x20, 0x73, 0x61, 0x6E, 0x73, 0x2D, 0x73, 0x65, 0x72, 0x69, 0x66, 0x3B, 0x0A, 0x7D, 
0x0A, 0x0A, 0x68, 0x31, 0x7B, 0x0A, 0x09, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3A, 0x20, 0x62, 0x6C, 
0x61, 0x63, 0x6B, 0x3B, 0x0A, 0x09, 0x74, 0x65, 0x78, 0x74, 0x2D, 0x61, 0x6C, 0x69, 0x67, 0x6E, 
0x3A, 0x20, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x23, 0x70, 0x72, 
0x6F, 0x63, 0x65, 0x73, 0x73, 0x7B, 0x0A, 0x09, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 
0x3A, 0x20, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6E, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 
0x6C, 0x65, 0x7B, 0x0A, 0x09, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3A, 0x20, 0x31, 0x30, 0x30, 0x25, 
0x3B, 0x0A, 0x09, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x3A, 0x20, 0x31, 0x70, 0x78, 0x20, 0x73, 
0x6F, 0x6C, 0x69, 0x64, 0x20, 0x23, 0x61, 0x61, 0x61, 0x3B, 0x20, 0x0A, 0x09, 0x62, 0x61, 0x63, 
0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x3A, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x3B, 0x0A, 
0x09, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x2D, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3A, 0x20, 
0x35, 0x70, 0x78, 0x3B, 0x0A, 0x09, 0x2D, 0x6D, 0x6F, 0x7A, 0x2D, 0x62, 0x6F, 0x72, 0x64, 0x65, 
0x72, 0x2D, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3A, 0x20, 0x35, 0x70, 0x78, 0x3B, 0x0A, 0x7D, 
0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x7B, 0x0A, 0x09, 0x62, 0x61, 0x63, 
0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x3A, 0x20, 0x23, 0x65, 0x65, 0x65, 0x3B, 0x0A, 0x7D, 
0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x2C, 0x20, 0x74, 0x61, 0x62, 0x6C, 
0x65, 0x20, 0x74, 0x64, 0x7B, 0x0A, 0x09, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3A, 0x20, 0x31, 0x30, 
0x65, 0x6D, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x2E, 0x75, 0x69, 
0x64, 0x7B, 0x0A, 0x09, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3A, 0x20, 0x31, 0x35, 0x65, 0x6D, 0x3B, 
0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x65, 0x61, 0x64, 0x7B, 
0x0A, 0x09, 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x79, 0x3A, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 
0x3B, 0x0A, 0x09, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3A, 0x20, 0x31, 0x30, 0x30, 0x25, 0x3B, 0x0A, 
0x7D, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x7B, 0x0A, 0x09, 
0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x3A, 0x20, 0x61, 0x75, 0x74, 0x6F, 0x3B, 0x0A, 
0x09, 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x79, 0x3A, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x3B, 
0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x20, 
0x74, 0x72, 0x2E, 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, 0x64, 0x7B, 0x0A, 0x09, 0x62, 0x61, 0x63, 
0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x3A, 0x20, 0x72, 0x65, 0x64, 0x3B, 0x0A, 0x7D, 0x0A, 
0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x74, 0x72, 0x2E, 
0x6E, 0x65, 0x77, 0x7B, 0x0A, 0x09, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 
0x3A, 0x20, 0x67, 0x72, 0x65, 0x65, 0x6E, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 
0x65, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x74, 0x72, 0x3A, 0x68, 0x6F, 0x76, 0x65, 0x72, 
0x7B, 0x0A, 0x09, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x3A, 0x20, 0x79, 
0x65, 0x6C, 0x6C, 0x6F, 0x77, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x0A, 0x3C, 0x2F, 0x73, 0x74, 0x79, 
0x6C, 0x65, 0x3E, 0x0A, 0x20, 0x3C, 0x2F, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x3E, 0x0A, 0x3C, 
0x62, 0x6F, 0x64, 0x79, 0x3E, 0x0A, 0x3C, 0x68, 0x31, 0x3E, 0x4F, 0x6E, 0x69, 0x6F, 0x6E, 0x20, 
0x54, 0x6F, 0x70, 0x3C, 0x2F, 0x68, 0x31, 0x3E, 0x0A, 0x0A, 0x3C, 0x64, 0x69, 0x76, 0x20, 0x69, 
0x64, 0x3D, 0x22, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x22, 0x3E, 0x0A, 0x3C, 0x74, 0x61, 
0x62, 0x6C, 0x65, 0x3E, 0x0A, 0x3C, 0x74, 0x68, 0x65, 0x61, 0x64, 0x3E, 0x0A, 0x3C, 0x74, 0x72, 
0x3E, 0x3C, 0x74, 0x68, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x70, 0x69, 0x64, 0x22, 
0x3E, 0x50, 0x49, 0x44, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 0x68, 0x20, 0x63, 0x6C, 0x61, 
0x73, 0x73, 0x3D, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3E, 0x43, 0x6F, 0x6D, 0x6D, 0x61, 0x6E, 
0x64, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 0x68, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 
0x22, 0x75, 0x69, 0x64, 0x22, 0x3E, 0x55, 0x69, 0x64, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 
0x68, 0x3E, 0x50, 0x50, 0x69, 0x64, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 0x68, 0x3E, 0x52, 
0x53, 0x53, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 0x68, 0x3E, 0x44, 0x61, 0x74, 0x61, 0x3C, 
0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 0x68, 0x3E, 0x4C, 0x69, 0x62, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 
0x3C, 0x74, 0x64, 0x3E, 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x0A, 0x3C, 0x2F, 0x74, 0x68, 0x65, 0x61, 
0x64, 0x3E, 0x0A, 0x3C, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x0A, 0x3C, 0x2F, 0x74, 0x62, 0x6F, 
0x64, 0x79, 0x3E, 0x0A, 0x3C, 0x2F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x3E, 0x0A, 0x3C, 0x2F, 0x64, 
0x69, 0x76, 0x3E, 0x0A, 0x0A, 0x3C, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3E, 0x0A, 0x24, 0x28, 
0x64, 0x6F, 0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x29, 0x2E, 0x72, 0x65, 0x61, 0x64, 0x79, 0x28, 
0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x28, 0x29, 0x7B, 0x0A, 0x09, 0x75, 0x70, 0x64, 
0x61, 0x74, 0x65, 0x54, 0x6F, 0x70, 0x28, 0x29, 0x0A, 0x7D, 0x29, 0x0A, 0x0A, 0x2F, 0x2A, 0x2A, 
0x0A, 0x20, 0x2A, 0x20, 0x40, 0x73, 0x68, 0x6F, 0x72, 0x74, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 
0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6F, 0x70, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x2E, 
0x0A, 0x20, 0x2A, 0x2F, 0x0A, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6F, 0x70, 0x20, 0x3D, 
0x20, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x28, 0x29, 0x7B, 0x0A, 0x09, 0x76, 0x61, 
0x72, 0x20, 0x70, 0x3D, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 
0x74, 0x62, 0x6F, 0x64, 0x79, 0x27, 0x29, 0x0A, 0x09, 0x76, 0x61, 0x72, 0x20, 0x58, 0x3D, 0x77, 
0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2E, 0x70, 0x61, 0x67, 0x65, 0x58, 0x4F, 0x66, 0x66, 0x73, 0x65, 
0x74, 0x0A, 0x09, 0x76, 0x61, 0x72, 0x20, 0x59, 0x3D, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2E, 
0x70, 0x61, 0x67, 0x65, 0x59, 0x4F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x0A, 0x09, 0x24, 0x2E, 0x67, 
0x65, 0x74, 0x28, 0x27, 0x2F, 0x70, 0x73, 0x2F, 0x27, 0x2C, 0x20, 0x66, 0x75, 0x6E, 0x63, 0x74, 
0x69, 0x6F, 0x6E, 0x28, 0x6F, 0x72, 0x69, 0x67, 0x29, 0x7B, 0x0A, 0x09, 0x09, 0x6F, 0x3D, 0x6F, 
0x72, 0x69, 0x67, 0x0A, 0x09, 0x09, 0x64, 0x3D, 0x24, 0x2E, 0x70, 0x61, 0x72, 0x73, 0x65, 0x4A, 
0x53, 0x4F, 0x4E, 0x28, 0x6F, 0x72, 0x69, 0x67, 0x29, 0x0A, 0x09, 0x09, 0x24, 0x28, 0x27, 0x74, 
0x72, 0x2E, 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, 0x64, 0x27, 0x29, 0x2E, 0x72, 0x65, 0x6D, 0x6F, 
0x76, 0x65, 0x28, 0x29, 0x0A, 0x09, 0x09, 0x76, 0x61, 0x72, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x73, 
0x3D, 0x70, 0x2E, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x72, 0x65, 0x6E, 0x28, 0x27, 0x74, 0x72, 0x27, 
0x29, 0x0A, 0x09, 0x09, 0x6C, 0x69, 0x6E, 0x65, 0x73, 0x2E, 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, 
0x43, 0x6C, 0x61, 0x73, 0x73, 0x28, 0x27, 0x6E, 0x65, 0x77, 0x27, 0x2C, 0x27, 0x73, 0x6C, 0x6F, 
0x77, 0x27, 0x29, 0x0A, 0x0A, 0x09, 0x09, 0x66, 0x6F, 0x72, 0x28, 0x6B, 0x20, 0x69, 0x6E, 0x20, 
0x64, 0x29, 0x7B, 0x0A, 0x09, 0x09, 0x09, 0x76, 0x61, 0x72, 0x20, 0x6C, 0x3D, 0x64, 0x5B, 0x6B, 
0x5D, 0x0A, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x6B, 0x21, 0x3D, 0x2D, 0x31, 0x29, 0x7B, 
0x0A, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x6C, 0x69, 0x6E, 0x65, 0x73, 0x2E, 0x66, 
0x69, 0x6C, 0x74, 0x65, 0x72, 0x28, 0x27, 0x23, 0x27, 0x2B, 0x6B, 0x29, 0x2E, 0x6C, 0x65, 0x6E, 
0x67, 0x74, 0x68, 0x29, 0x7B, 0x20, 0x2F, 0x2F, 0x20, 0x61, 0x6C, 0x72, 0x65, 0x61, 0x64, 0x79, 
0x20, 0x68, 0x65, 0x72, 0x65, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6C, 0x69, 0x6E, 0x65, 0x73, 
0x3D, 0x6C, 0x69, 0x6E, 0x65, 0x73, 0x2E, 0x6E, 0x6F, 0x74, 0x28, 0x27, 0x23, 0x27, 0x2B, 0x6B, 
0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x7D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6C, 0x73, 0x65, 
0x7B, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x76, 0x61, 0x72, 0x20, 0x74, 0x72, 0x3D, 0x24, 0x28, 
0x27, 0x3C, 0x74, 0x72, 0x3E, 0x27, 0x29, 0x2E, 0x61, 0x74, 0x74, 0x72, 0x28, 0x27, 0x69, 0x64, 
0x27, 0x2C, 0x6B, 0x29, 0x2E, 0x61, 0x64, 0x64, 0x43, 0x6C, 0x61, 0x73, 0x73, 0x28, 0x27, 0x6E, 
0x65, 0x77, 0x27, 0x29, 0x2E, 0x66, 0x61, 0x64, 0x65, 0x49, 0x6E, 0x28, 0x27, 0x73, 0x6C, 0x6F, 
0x77, 0x27, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 0x61, 0x70, 0x70, 0x65, 
0x6E, 0x64, 0x28, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x64, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 
0x22, 0x70, 0x69, 0x64, 0x22, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6B, 0x29, 
0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 
0x28, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x64, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x6E, 
0x61, 0x6D, 0x65, 0x22, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6C, 0x5B, 0x27, 
0x4E, 0x61, 0x6D, 0x65, 0x27, 0x5D, 0x29, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 
0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x64, 0x20, 0x63, 
0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x75, 0x69, 0x64, 0x22, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 
0x78, 0x74, 0x28, 0x6C, 0x5B, 0x27, 0x55, 0x69, 0x64, 0x27, 0x5D, 0x29, 0x29, 0x0A, 0x09, 0x09, 
0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x24, 0x28, 0x27, 
0x3C, 0x74, 0x64, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6C, 0x5B, 0x27, 0x50, 
0x50, 0x69, 0x64, 0x27, 0x5D, 0x29, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 
0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x64, 0x3E, 0x27, 0x29, 
0x2E, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6C, 0x5B, 0x27, 0x56, 0x6D, 0x52, 0x53, 0x53, 0x27, 0x5D, 
0x29, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 
0x64, 0x28, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x64, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78, 0x74, 
0x28, 0x6C, 0x5B, 0x27, 0x56, 0x6D, 0x44, 0x61, 0x74, 0x61, 0x27, 0x5D, 0x29, 0x29, 0x0A, 0x09, 
0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x24, 0x28, 
0x27, 0x3C, 0x74, 0x64, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6C, 0x5B, 0x27, 
0x56, 0x6D, 0x4C, 0x69, 0x62, 0x27, 0x5D, 0x29, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x70, 
0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x74, 0x72, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 
0x7D, 0x0A, 0x09, 0x09, 0x09, 0x7D, 0x0A, 0x09, 0x09, 0x7D, 0x0A, 0x0A, 0x09, 0x09, 0x6C, 0x69, 
0x6E, 0x65, 0x73, 0x2E, 0x61, 0x64, 0x64, 0x43, 0x6C, 0x61, 0x73, 0x73, 0x28, 0x27, 0x72, 0x65, 
0x6D, 0x6F, 0x76, 0x65, 0x64, 0x27, 0x29, 0x2E, 0x66, 0x61, 0x64, 0x65, 0x4F, 0x75, 0x74, 0x28, 
0x27, 0x73, 0x6C, 0x6F, 0x77, 0x27, 0x29, 0x0A, 0x0A, 0x09, 0x09, 0x2F, 0x2F, 0x20, 0x63, 0x6F, 
0x70, 0x79, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x64, 
0x65, 0x72, 0x2E, 0x0A, 0x09, 0x09, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 
0x73, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x74, 0x64, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 
0x74, 0x68, 0x28, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 
0x68, 0x2E, 0x70, 0x69, 0x64, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x2B, 
0x33, 0x29, 0x0A, 0x09, 0x09, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 
0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x74, 0x64, 0x2E, 0x75, 0x69, 0x64, 0x27, 0x29, 0x2E, 
0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 
0x73, 0x20, 0x74, 0x68, 0x2E, 0x75, 0x69, 0x64, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 0x74, 0x68, 
0x28, 0x29, 0x29, 0x0A, 0x09, 0x09, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 
0x73, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x2E, 0x6E, 0x61, 0x6D, 0x65, 0x27, 0x29, 0x2E, 
0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 
0x73, 0x20, 0x74, 0x68, 0x65, 0x61, 0x64, 0x20, 0x2E, 0x6E, 0x61, 0x6D, 0x65, 0x27, 0x29, 0x2E, 
0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x29, 0x0A, 0x09, 0x7D, 0x2C, 0x27, 0x70, 0x6C, 0x61, 
0x69, 0x6E, 0x27, 0x29, 0x0A, 0x09, 0x0A, 0x09, 0x63, 0x68, 0x65, 0x63, 0x6B, 0x53, 0x69, 0x7A, 
0x65, 0x28, 0x29, 0x3B, 0x0A, 0x09, 0x24, 0x28, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x29, 0x2E, 
0x72, 0x65, 0x73, 0x69, 0x7A, 0x65, 0x28, 0x63, 0x68, 0x65, 0x63, 0x6B, 0x53, 0x69, 0x7A, 0x65, 
0x29, 0x0A, 0x0A, 0x09, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2E, 0x73, 0x63, 0x72, 0x6F, 0x6C, 
0x6C, 0x54, 0x6F, 0x28, 0x58, 0x2C, 0x59, 0x29, 0x0A, 0x09, 0x73, 0x65, 0x74, 0x54, 0x69, 0x6D, 
0x65, 0x6F, 0x75, 0x74, 0x28, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6F, 0x70, 0x2C, 0x32, 
0x2A, 0x31, 0x30, 0x30, 0x30, 0x29, 0x0A, 0x7D, 0x0A, 0x0A, 0x63, 0x68, 0x65, 0x63, 0x6B, 0x53, 
0x69, 0x7A, 0x65, 0x20, 0x3D, 0x20, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x28, 0x29, 
0x7B, 0x0A, 0x09, 0x2F, 0x2F, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 
0x27, 0x29, 0x2E, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 
0x2E, 0x69, 0x6E, 0x6E, 0x65, 0x72, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2D, 0x31, 0x30, 0x30, 
0x29, 0x3B, 0x0A, 0x09, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 
0x74, 0x62, 0x6F, 0x64, 0x79, 0x27, 0x29, 0x2E, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x77, 
0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2E, 0x69, 0x6E, 0x6E, 0x65, 0x72, 0x48, 0x65, 0x69, 0x67, 0x68, 
0x74, 0x2D, 0x24, 0x28, 0x27, 0x2E, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x43, 0x6F, 0x6E, 0x74, 0x61, 
0x69, 0x6E, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x61, 0x64, 0x27, 0x29, 0x2E, 0x68, 0x65, 0x69, 
0x67, 0x68, 0x74, 0x28, 0x29, 0x2D, 0x31, 0x31, 0x35, 0x29, 0x3B, 0x0A, 0x09, 0x24, 0x28, 0x27, 
0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x61, 0x64, 0x20, 0x2E, 
0x6E, 0x61, 0x6D, 0x65, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x24, 0x28, 0x27, 
0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 0x74, 0x68, 
0x28, 0x29, 0x29, 0x0A, 0x0A, 0x7D, 0x0A, 0x0A, 0x3C, 0x2F, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 
0x3E, 0x0A, 0x0A, 0x3C, 0x2F, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x0A, };
  onion_response_set_length(res, 2507);
  return onion_response_write(res, data, sizeof(data));
}
Exemplo n.º 16
0
/**
 * @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;
}
Exemplo n.º 17
0
 void setLength(size_t length){
   onion_response_set_length(ptr,length);
 }
Exemplo n.º 18
0
Arquivo: url.c Projeto: cemonds/onion
/// Handles the write of static data
static int onion_url_static(struct onion_url_static_data *data, onion_request *req, onion_response *res){
	onion_response_set_code(res, data->code);
	onion_response_set_length(res, strlen(data->text));
	onion_response_write0(res, data->text);
	return OCS_PROCESSED;
}