/** * @short Performs the processing of the request. * @memberof onion_server_t * * Returns the OCS_KEEP_ALIVE or OCS_CLOSE_CONNECTION value. If on keep alive the struct is already reinitialized. * * It calls the root_handler and if it returns an error of any type (or not processed), it calls the * default internal_error_handler. * * Normally it could get the server from the request, but it is passed for homogenity, and * to allow unforseen posibilities. * * @see onion_connection_status */ onion_connection_status onion_server_handle_request(onion_server *server, onion_request *req){ onion_response *res=onion_response_new(req); // Call the main handler. onion_connection_status hs=onion_handler_handle(server->root_handler, req, res); if (hs==OCS_INTERNAL_ERROR || hs==OCS_NOT_IMPLEMENTED || hs==OCS_NOT_PROCESSED){ if (hs==OCS_INTERNAL_ERROR) req->flags|=OR_INTERNAL_ERROR; if (hs==OCS_NOT_IMPLEMENTED) req->flags|=OR_NOT_IMPLEMENTED; if (hs==OCS_NOT_PROCESSED) req->flags|=OR_NOT_FOUND; if (hs==OCS_FORBIDDEN) req->flags|=OR_FORBIDDEN; hs=onion_handler_handle(server->internal_error_handler, req, res); } int rs=onion_response_free(res); if (hs>=0 && rs==OCS_KEEP_ALIVE) // if keep alive, reset struct to get the new petition. onion_request_clean(req); return hs>0 ? rs : hs; }
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; }
void t01_handle_static_request(){ INIT_LOCAL(); char ok; onion *server=onion_new(0); onion_listen_point *lp=onion_buffer_listen_point_new(); onion_add_listen_point(server, NULL, NULL, lp); onion_request *request=onion_request_new(lp); FILL(request,"GET / HTTP/1.1\n"); onion_handler *handler=onion_handler_static("Not ready",302); FAIL_IF_NOT(handler); onion_set_root_handler(server, handler); onion_response *response=onion_response_new(request); ok=onion_handler_handle(handler, request, response); FAIL_IF_NOT_EQUAL(ok, OCS_PROCESSED); onion_response_free(response); const char *buffer=onion_buffer_listen_point_get_buffer_data(request); FAIL_IF_EQUAL_STR(buffer,""); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 302 REDIRECT\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\nContent-Length: 9\r\n"); FAIL_IF_NOT_STRSTR(buffer, "libonion"); FAIL_IF_STRSTR(buffer, "License: AGPL"); // License is now LGPL, no need to advertise FAIL_IF_STRSTR(buffer, "License"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nNot ready"); onion_request_free(request); onion_free(server); END_LOCAL(); }
/** * @short Performs the real request: checks if its for me, and then calls the inside level. */ int onion_url_handler(onion_url_data **dd, onion_request *request, onion_response *response){ onion_url_data *next=*dd; regmatch_t match[16]; int i; const char *path=onion_request_get_path(request); while (next){ ONION_DEBUG0("Check %s against %s", onion_request_get_path(request), next->orig); if (next->flags&OUD_STRCMP){ if (strcmp(path, next->str)==0){ ONION_DEBUG0("Ok, simple match."); onion_request_advance_path(request, strlen(next->str)); return onion_handler_handle(next->inside, request, response); } } else if (regexec(&next->regexp, onion_request_get_path(request), 16, match, 0)==0){ //ONION_DEBUG("Ok,match"); onion_dict *reqheader=request->GET; for (i=1;i<16;i++){ regmatch_t *rm=&match[i]; if (rm->rm_so!=-1){ char *tmp=malloc(rm->rm_eo-rm->rm_so); memcpy(tmp, &path[rm->rm_so], rm->rm_eo-rm->rm_so); char tmpn[4]; snprintf(tmpn,sizeof(tmpn),"%d",i); onion_dict_add(reqheader, tmpn, tmp, OD_DUP_KEY|OD_FREE_VALUE); ONION_DEBUG("Add group %d: %s (%d-%d)", i, tmp, rm->rm_so, rm->rm_eo); } else break; } onion_request_advance_path(request, match[0].rm_eo); ONION_DEBUG0("Ok, regexp match."); return onion_handler_handle(next->inside, request, response); } next=next->next; } return 0; }
int oterm_nopam(onion_handler *next, onion_request *req, onion_response *res){ onion_dict *session=onion_request_get_session_dict(req); onion_dict_lock_write(session); const char *username=getenv("USER"); if (username) onion_dict_add(session, "username", username, 0); onion_dict_add(session, "nopam", "true", 0); onion_dict_unlock(session); return onion_handler_handle(next, req, res); }
/** * @short Launches one handler for the given request * @ingroup request * * Once the request is ready, launch it. * * @returns The connection status: if it should be closed, error codes... */ onion_connection_status onion_request_process(onion_request *req){ onion_response *res=onion_response_new(req); if (!req->path){ onion_request_polish(req); } // Call the main handler. onion_connection_status hs=onion_handler_handle(req->connection.listen_point->server->root_handler, req, res); if (hs==OCS_INTERNAL_ERROR || hs==OCS_NOT_IMPLEMENTED || hs==OCS_NOT_PROCESSED){ if (hs==OCS_INTERNAL_ERROR) req->flags|=OR_INTERNAL_ERROR; if (hs==OCS_NOT_IMPLEMENTED) req->flags|=OR_NOT_IMPLEMENTED; if (hs==OCS_NOT_PROCESSED) req->flags|=OR_NOT_FOUND; if (hs==OCS_FORBIDDEN) req->flags|=OR_FORBIDDEN; hs=onion_handler_handle(req->connection.listen_point->server->internal_error_handler, req, res); } if (hs==OCS_YIELD){ // Remove from the poller, and yield thread to poller. From now on it will be processed somewhere else (longpoll thread). onion_poller *poller=onion_get_poller(req->connection.listen_point->server); onion_poller_slot *slot=onion_poller_get(poller, req->connection.fd); onion_poller_slot_set_shutdown(slot, NULL, NULL); return hs; } int rs=onion_response_free(res); if (hs>=0 && rs==OCS_KEEP_ALIVE) // if keep alive, reset struct to get the new petition. onion_request_clean(req); return hs>0 ? rs : hs; }
void t03_handle_path_request(){ INIT_LOCAL(); onion *server=onion_new(0); onion_listen_point *lp=onion_buffer_listen_point_new(); onion_add_listen_point(server, NULL, NULL, lp); onion_url *urls=onion_url_new(); onion_url_add_static(urls, "^$", "Test index\n", HTTP_OK); onion_url_add_static(urls, "^index.html$", "Index test", 200); onion_url *pathu=onion_url_new(); onion_handler *path=onion_url_to_handler(pathu); onion_url_add_url(pathu, "^test/", urls); onion_handler_add(path, onion_handler_static("Internal error", 500 ) ); onion_set_root_handler(server, path); onion_request *request; onion_response *response; request=onion_request_new(lp); FILL(request,"GET / HTTP/1.1\n"); onion_request_polish(request); response=onion_response_new(request); onion_handler_handle(path, request, response); onion_response_free(response); const char *buffer=onion_buffer_listen_point_get_buffer_data(request); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 500 INTERNAL ERROR\r\n"); FAIL_IF_NOT_STRSTR(buffer, "Content-Length: 14\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nInternal error"); onion_request_free(request); // gives error, as such url does not exist. request=onion_request_new(lp); FILL(request,"GET /test/ HTTP/1.1\n"); onion_request_polish(request); response=onion_response_new(request); onion_handler_handle(path, request, response); onion_response_free(response); buffer=onion_buffer_listen_point_get_buffer_data(request); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 200 OK\r\n"); FAIL_IF_NOT_STRSTR(buffer, "Content-Length: 11\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nTest index\n"); onion_request_free(request); request=onion_request_new(lp); FILL(request,"GET /test/index.html HTTP/1.1\n"); onion_request_polish(request); response=onion_response_new(request); onion_handler_handle(path, request, response); onion_response_free(response); buffer=onion_buffer_listen_point_get_buffer_data(request); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 200 OK\r\n"); FAIL_IF_NOT_STRSTR(buffer, "Content-Length: 10\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nIndex test"); onion_request_free(request); onion_free(server); END_LOCAL(); }
/// Shortcut for fast internal redirect. It returns what the server would return with the new address. onion_connection_status onion_shortcut_internal_redirect(const char *newurl, onion_request *req, onion_response *res){ free(req->fullpath); req->fullpath=req->path=strdup(newurl); return onion_handler_handle(req->connection.listen_point->server->root_handler, req, res); }