smcp_status_t smcp_auth_verify_request() { smcp_status_t ret = SMCP_STATUS_OK; coap_option_key_t key; const uint8_t* authvalue; size_t authvalue_len; // For testing purposes only! if(smcp_inbound_get_code() >1 && smcp_inbound_get_code()<COAP_RESULT_100) { ret = SMCP_STATUS_UNAUTHORIZED; } smcp_inbound_reset_next_option(); while((key = smcp_inbound_next_option(&authvalue,&authvalue_len))!=COAP_OPTION_INVALID) { if(key==COAP_OPTION_PROXY_URI) { // For testing purposes only! ret = SMCP_STATUS_OK; } if(key==COAP_OPTION_AUTHENTICATE) { // For testing purposes only! ret = SMCP_STATUS_OK; // writeme! } } if(smcp_inbound_origin_is_local()) { ret = SMCP_STATUS_OK; } ret = SMCP_STATUS_OK; // For testing purposes only! if(ret==SMCP_STATUS_UNAUTHORIZED) { smcp_outbound_begin_response(COAP_RESULT_401_UNAUTHORIZED); smcp_outbound_add_option(COAP_OPTION_AUTHENTICATE,NULL,0); smcp_outbound_send(); } return ret; }
smcp_status_t smcp_node_route(smcp_node_t node, smcp_request_handler_func* func, void** context) { smcp_status_t ret = 0; smcp_t const self = smcp_get_current_instance(); smcp_inbound_reset_next_option(); { // TODO: Rewrite this to be more efficient. const uint8_t* prev_option_ptr = self->inbound.this_option; coap_option_key_t prev_key = 0; coap_option_key_t key; const uint8_t* value; coap_size_t value_len; while ((key = smcp_inbound_next_option(&value, &value_len)) != COAP_OPTION_INVALID) { if (key > COAP_OPTION_URI_PATH) { self->inbound.this_option = prev_option_ptr; self->inbound.last_option_key = prev_key; break; } else if (key == COAP_OPTION_URI_PATH) { smcp_node_t next = smcp_node_find( node, (const char*)value, (int)value_len ); if (next) { node = next; } else { self->inbound.this_option = prev_option_ptr; self->inbound.last_option_key = prev_key; break; } } else if(key==COAP_OPTION_URI_HOST) { // Skip host at the moment, // because we don't do virtual hosting yet. } else if(key==COAP_OPTION_URI_PORT) { // Skip port at the moment, // because we don't do virtual hosting yet. } else if(key==COAP_OPTION_PROXY_URI) { // Skip the proxy URI for now. } else if(key==COAP_OPTION_CONTENT_TYPE) { // Skip. } else { if(COAP_OPTION_IS_CRITICAL(key)) { ret=SMCP_STATUS_BAD_OPTION; assert_printf("Unrecognized option %d, \"%s\"", key, coap_option_key_to_cstr(key, false) ); goto bail; } } prev_option_ptr = self->inbound.this_option; prev_key = self->inbound.last_option_key; } } *func = (void*)node->request_handler; if(node->context) { *context = node->context; } else { *context = (void*)node; } bail: return ret; }
smcp_status_t smcp_curl_proxy_request_handler( smcp_curl_proxy_node_t node ) { smcp_status_t ret = SMCP_STATUS_NOT_ALLOWED; smcp_curl_request_t request = NULL; struct curl_slist *headerlist=NULL; smcp_method_t method = smcp_inbound_get_code(); //require_action(method<=COAP_METHOD_DELETE,bail,ret = SMCP_STATUS_NOT_ALLOWED); //require_action(COAP_OPTION_URI_PATH!=smcp_inbound_peek_option(NULL,NULL),bail,ret=SMCP_STATUS_NOT_FOUND); node->interface = smcp_get_current_instance(); smcp_inbound_reset_next_option(); request = smcp_curl_request_create(); request->proxy_node = node; require_action(request!=NULL,bail,ret = SMCP_STATUS_MALLOC_FAILURE); switch(method) { case COAP_METHOD_GET: curl_easy_setopt(request->curl, CURLOPT_CUSTOMREQUEST, "GET"); break; case COAP_METHOD_PUT: curl_easy_setopt(request->curl, CURLOPT_PUT, 1L); break; case COAP_METHOD_POST: curl_easy_setopt(request->curl, CURLOPT_POST, 1L); break; case COAP_METHOD_DELETE: curl_easy_setopt(request->curl, CURLOPT_CUSTOMREQUEST, "DELETE"); break; default: ret = SMCP_STATUS_NOT_ALLOWED; break; } { coap_option_key_t key; const uint8_t* value; coap_size_t value_len; while((key=smcp_inbound_next_option(&value, &value_len))!=COAP_OPTION_INVALID) { if(key==COAP_OPTION_PROXY_URI) { char uri[value_len+1]; memcpy(uri,value,value_len); uri[value_len] = 0; curl_easy_setopt(request->curl, CURLOPT_URL, uri); assert_printf("CuRL URL: \"%s\"",uri); ret = 0; } else if(key==COAP_OPTION_URI_HOST) { } else if(key==COAP_OPTION_URI_PORT) { } else if(key==COAP_OPTION_URI_PATH) { } else if(key==COAP_OPTION_URI_QUERY) { } else if(key==COAP_OPTION_CONTENT_TYPE || key==COAP_OPTION_ACCEPT) { const char* option_name = coap_option_key_to_cstr(key, false); const char* value_string = coap_content_type_to_cstr(value[1]); char header[strlen(option_name)+strlen(value_string)+3]; strcpy(header,option_name); strcat(header,": "); strcat(header,value_string); headerlist = curl_slist_append(headerlist, header); assert_printf("CuRL HEADER: \"%s\"",header); } else { if(coap_option_value_is_string(key)) { const char* option_name = coap_option_key_to_cstr(key, false); char header[strlen(option_name)+value_len+3]; strcpy(header,option_name); strcat(header,": "); strncat(header,(const char*)value,value_len); assert_printf("CuRL HEADER: \"%s\"",header); headerlist = curl_slist_append(headerlist, header); } } } } require_noerr(ret,bail); if(smcp_inbound_get_content_len()) { coap_size_t len = smcp_inbound_get_content_len(); request->output_content = calloc(1,len+1); request->output_content_len = len; memcpy(request->output_content,smcp_inbound_get_content_ptr(),len); curl_easy_setopt(request->curl, CURLOPT_READFUNCTION, ReadMemoryCallback); curl_easy_setopt(request->curl, CURLOPT_READDATA, (void *)request); } curl_easy_setopt(request->curl, CURLOPT_USERAGENT, "smcp-curl-proxy/1.0"); curl_easy_setopt(request->curl, CURLOPT_HTTPHEADER, headerlist),headerlist=NULL; curl_easy_setopt(request->curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(request->curl, CURLOPT_WRITEDATA, (void *)request); ret = smcp_start_async_response(&request->async_response,0); require_noerr(ret,bail); if(node->curl_multi_handle) curl_multi_add_handle(node->curl_multi_handle, request->curl); else curl_easy_perform(request->curl); bail: if(headerlist) curl_slist_free_all(headerlist); if(ret && request) smcp_curl_request_release(request); return ret; }