diff --git a/core/api.c b/core/api.c index 06bbf1f..33418f4 100644 --- a/core/api.c +++ b/core/api.c @@ -333,6 +333,20 @@ struct ApiConnectionParam { struct IpfsNode* this_node; }; +/*** + * Take an s_request and turn it into an HttpRequest + * @param req the incoming s_request + * @returns the resultant HttpRequest or NULL on error + */ +struct HttpRequest* api_build_http_request(struct s_request* req) { + struct HttpRequest* request = ipfs_core_http_request_new(); + if (request != NULL) { + request->command = req->buf + req->method; + //TODO: Complete this method + } + return request; +} + /** * Pthread to take care of each client connection. * @param ptr an ApiConnectionParam @@ -420,11 +434,10 @@ void *api_connection_thread (void *ptr) goto quit; } - struct HttpRequest* http_request = ipfs_core_http_request_new(); + // once we leave the building of the req struct, do we need to do more? This flag will tell us. + int further_processing_necessary = 1; + if (strcmp(buf + req.method, "GET")==0) { - char *path; - unsigned char *obj; - size_t size; if (strcmp (req.buf + req.path, "/")==0 || strcmp (req.buf + req.path, "/webui") || @@ -441,23 +454,13 @@ void *api_connection_thread (void *ptr) } else { write_cstr (s, HTTP_500); } + further_processing_necessary = 0; } else { - //TODO: build http_request here - path = req.buf + req.path; - - if (get_object(params->this_node, path, &obj, &size)) { - if (!send_object(s, obj, size)) { - libp2p_logger_error("api", "fail send_object.\n"); - } - free(obj); - } else { - // object not found. - write_dual (s, req.buf + req.http_ver, strchr (HTTP_404, ' ')); - } + // move out of the if to do further processing } + // end of GET } else if (strcmp(buf + req.method, "POST")==0) { // TODO: Handle gzip/json POST requests. - // TODO: build http_request here p = header_value_cmp(&req, "Content-Type:", "multipart/form-data;"); if (p) { @@ -490,39 +493,51 @@ void *api_connection_thread (void *ptr) } } } - // TODO: Parse the path var and decide what to do with the received data. + if (req.boundary > 0) { libp2p_logger_error("api", "boundary index = %d, size = %d\n", req.boundary, req.boundary_size); } - libp2p_logger_error("api", "method = '%s'\n" + libp2p_logger_debug("api", "method = '%s'\n" "path = '%s'\n" "http_ver = '%s'\n" "header {\n%s\n}\n" "body_size = %d\n", req.buf+req.method, req.buf+req.path, req.buf+req.http_ver, req.buf+req.header, req.body_size); - - char* response_text = NULL; - if (!ipfs_core_http_request_process(http_request, &response_text)) { - libp2p_logger_error("api", "ipfs_core_http_request_process returned false.\n"); - // TODO: Handle this condition - } - ipfs_core_http_request_free(http_request); - - snprintf(resp, sizeof(resp), "%s 200 OK\r\n" \ - "Content-Type: application/json\r\n" - "Server: c-ipfs/0.0.0-dev\r\n" - "X-Chunked-Output: 1\r\n" - "Connection: close\r\n" - "Transfer-Encoding: chunked\r\n\r\n%s", req.buf + req.http_ver, response_text); - free(response_text); - write_str (s, resp); - libp2p_logger_error("api", "resp = {\n%s\n}\n", resp); + // end of POST } else { // Unexpected??? libp2p_logger_error("api", "fail unexpected '%s'.\n", req.buf + req.method); write_cstr (s, HTTP_500); + further_processing_necessary = 0; + } + + if (further_processing_necessary) { + // now do something with the request we have built + struct HttpRequest* http_request = api_build_http_request(&req); + if (http_request != NULL) { + char* response_text = NULL; + if (!ipfs_core_http_request_process(params->this_node, http_request, &response_text)) { + libp2p_logger_error("api", "ipfs_core_http_request_process returned false.\n"); + // TODO: Handle this condition + } + ipfs_core_http_request_free(http_request); + // now send the results + snprintf(resp, sizeof(resp), "%s 200 OK\r\n" \ + "Content-Type: application/json\r\n" + "Server: c-ipfs/0.0.0-dev\r\n" + "X-Chunked-Output: 1\r\n" + "Connection: close\r\n" + "Transfer-Encoding: chunked\r\n\r\n%s", req.buf + req.http_ver, response_text); + if (response_text != NULL) + free(response_text); + write_str (s, resp); + libp2p_logger_debug("api", "resp = {\n%s\n}\n", resp); + } else { + // uh oh... something went wrong converting to the HttpRequest struct + libp2p_logger_error("api", "Unable to build HttpRequest struct.\n"); + } } } else { libp2p_logger_error("api", "fail looking for body.\n"); diff --git a/core/http_request.c b/core/http_request.c index 679b0bb..4ec2cc2 100644 --- a/core/http_request.c +++ b/core/http_request.c @@ -1,6 +1,10 @@ #include +#include #include "libp2p/utils/vector.h" +#include "libp2p/utils/logger.h" #include "ipfs/core/http_request.h" +#include "ipfs/namesys/resolver.h" +#include "ipfs/namesys/publisher.h" /** * Handles HttpRequest and HttpParam @@ -27,10 +31,10 @@ struct HttpRequest* ipfs_core_http_request_new() { */ void ipfs_core_http_request_free(struct HttpRequest* request) { if (request != NULL) { - if (request->command != NULL) - free(request->command); - if (request->sub_command != NULL) - free(request->sub_command); + //if (request->command != NULL) + // free(request->command); + //if (request->sub_command != NULL) + // free(request->sub_command); if (request->params != NULL) { for(int i = 0; i < request->params->total; i++) { struct HttpParam* curr_param = (struct HttpParam*) libp2p_utils_vector_get(request->params, i); @@ -75,12 +79,147 @@ void ipfs_core_http_param_free(struct HttpParam* param) { } } +/*** + * Handle processing of the "name" command + * @param local_node the context + * @param request the incoming request + * @param response the response + * @returns true(1) on success, false(0) otherwise + */ +int ipfs_core_http_process_name(struct IpfsNode* local_node, struct HttpRequest* request, char** response) { + int retVal = 0; + char* path = NULL; + char* result = NULL; + if (request->arguments == NULL || request->arguments->total == 0) { + libp2p_logger_error("http_request", "process_name: empty arguments\n"); + return 0; + } + path = (char*) libp2p_utils_vector_get(request->arguments, 0); + if (strcmp(request->sub_command, "resolve") == 0) { + retVal = ipfs_namesys_resolver_resolve(local_node, path, 1, &result); + if (retVal) { + *response = (char*) malloc(strlen(result) + 20); + sprintf(*response, "{ \"Path\": \"%s\" }", result); + } + free(result); + } else if (strcmp(request->sub_command, "publish") == 0) { + retVal = ipfs_namesys_publisher_publish(local_node, path); + if (retVal) { + *response = (char*) malloc(strlen(local_node->identity->peer->id) + strlen(path) + 30); + sprintf(*response, "{ \"Name\": \"%s\"\n \"Value\": \"%s\" }", local_node->identity->peer->id, path); + } + } + return retVal; +} + +/*** + * Handle processing of the "object" command + * @param local_node the context + * @param request the incoming request + * @param response the response + * @returns true(1) on success, false(0) otherwise + */ +int ipfs_core_http_process_object(struct IpfsNode* local_node, struct HttpRequest* request, char** response) { + int retVal = 0; + if (strcmp(request->sub_command, "get") == 0) { + // do an object_get + } + return retVal; +} + /*** * Process the parameters passed in from an http request + * @param local_node the context * @param request the request * @param response the response * @returns true(1) on success, false(0) otherwise. */ -int ipfs_core_http_request_process(struct HttpRequest* request, char** response) { +int ipfs_core_http_request_process(struct IpfsNode* local_node, struct HttpRequest* request, char** response) { + if (request == NULL) + return 0; + int retVal = 0; + + if (strcmp(request->command, "name") == 0) { + retVal = ipfs_core_http_process_name(local_node, request, response); + } else if (strcmp(request->command, "object") == 0) { + retVal = ipfs_core_http_process_object(local_node, request, response); + } + return retVal; +} + +/** + * just builds the basics of an http api url + * @param local_node where to get the ip and port + * @returns a string in the form of "http://127.0.0.1:5001/api/v0" (or whatever was in the config file for the API) + */ +char* ipfs_core_http_request_build_url_start(struct IpfsNode* local_node) { + char* host = NULL; + char port[10] = ""; + struct MultiAddress* ma = multiaddress_new_from_string(local_node->repo->config->addresses->api); + if (ma == NULL) + return NULL; + if (!multiaddress_get_ip_address(ma, &host)) { + multiaddress_free(ma); + return 0; + } + int portInt = multiaddress_get_ip_port(ma); + sprintf(port, "%d", portInt); + int len = 18 + strlen(host) + strlen(port); + char* retVal = malloc(len); + sprintf(retVal, "http://%s:%s/api/v0", host, port); + free(host); + multiaddress_free(ma); + return retVal; +} + +/*** + * Adds commands to url + * @param request the request + * @param url the starting url, and will hold the results (i.e. http://127.0.0.1:5001/api/v0// + * @returns true(1) on success, otherwise false(0) + */ +int ipfs_core_http_request_add_commands(struct HttpRequest* request, char** url) { + // command + int addl_length = strlen(request->command) + 2; + char* string1 = (char*) malloc(strlen(*url) + addl_length); + sprintf(string1, "%s/%s", *url, request->command); + free(*url); + *url = string1; + // sub_command + if (request->sub_command != NULL) { + addl_length = strlen(request->sub_command) + 2; + string1 = (char*) malloc(strlen(*url) + addl_length); + sprintf(string1, "%s/%s", *url, request->sub_command); + free(*url); + *url = string1; + } + return 1; +} + +/** + * Do an HTTP Get to the local API + * @param local_node the context + * @param request the request + * @param result the results + * @returns true(1) on success, false(0) on error + */ +int ipfs_core_http_request_get(struct IpfsNode* local_node, struct HttpRequest* request, char** result) { + if (request == NULL || request->command == NULL) + return 0; + + char* url = ipfs_core_http_request_build_url_start(local_node); + if (url == NULL) + return 0; + + if (!ipfs_core_http_request_add_commands(request, &url)) { + free(url); + return 0; + } + + int request_length = 10 + strlen(request->command); + if (request->sub_command != NULL) + request_length += 1 + strlen(request->sub_command); + //TODO: continue building out this method return 0; } + diff --git a/include/ipfs/core/http_request.h b/include/ipfs/core/http_request.h index 8e2dca4..11bdfa3 100644 --- a/include/ipfs/core/http_request.h +++ b/include/ipfs/core/http_request.h @@ -1,5 +1,7 @@ #pragma once +#include "ipfs/core/ipfs_node.h" + /*** * A name/value pair of http parameters */ @@ -44,8 +46,18 @@ void ipfs_core_http_param_free(struct HttpParam* param); /*** * Process the parameters passed in from an http request + * @param local_node the context * @param request the request * @param response the response * @returns true(1) on success, false(0) otherwise. */ -int ipfs_core_http_request_process(struct HttpRequest* request, char** response); +int ipfs_core_http_request_process(struct IpfsNode* local_node, struct HttpRequest* request, char** response); + +/** + * Do an HTTP Get to the local API + * @param local_node the context + * @param request the request + * @param result the results + * @returns true(1) on success, false(0) on error + */ +int ipfs_core_http_request_get(struct IpfsNode* local_node, struct HttpRequest* request, char** result); diff --git a/namesys/name.c b/namesys/name.c index 44fbdea..35bf2b3 100644 --- a/namesys/name.c +++ b/namesys/name.c @@ -5,13 +5,24 @@ #include "libp2p/utils/logger.h" #include "ipfs/core/ipfs_node.h" #include "ipfs/cmd/cli.h" +#include "ipfs/core/http_request.h" /*** * Publish IPNS name */ int ipfs_name_publish(struct IpfsNode* local_node, char* name) { - // call api - return 0; + // call api. + char* response = NULL; + struct HttpRequest* request = ipfs_core_http_request_new(); + if (request == NULL) + return 0; + request->command = "name"; + request->sub_command = "publish"; + int retVal = ipfs_core_http_request_get(local_node, request, &response); + if (response != NULL) + free(response); + ipfs_core_http_request_free(request); + return retVal; } int ipfs_name_resolve(struct IpfsNode* local_node, char* name) {