/** * Launch simple commands (commands without file I/O) and return response * * @param url Target URL * @param method HTTP method (GET/PUT/POST) * @param followloc Whether or not need to set CURLOPT_FOLLOWLOCATION * @param response Response from remote service * @return 0 for success and non-zero value to indicate error */ static int launchCmd(const char *url, enum HttpHeader method, enum Redirect followloc, struct Response **response) { CURL *curl = NULL; CURLcode curlCode; int ret = 0; struct Response *resp = NULL; resp = calloc(1, sizeof(struct Response)); if (!resp) { return ENOMEM; } ret = initResponseBuffer(&(resp->body)); if (ret) { goto done; } ret = initResponseBuffer(&(resp->header)); if (ret) { goto done; } initCurlGlobal(); curl = curl_easy_init(); if (!curl) { ret = ENOMEM; // curl_easy_init does not return error code, // and most of its errors are caused by malloc() fprintf(stderr, "ERROR in curl_easy_init.\n"); goto done; } /* Set callback function for reading data from remote service */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc); curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp->body); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, writefunc); curl_easy_setopt(curl, CURLOPT_WRITEHEADER, resp->header); curl_easy_setopt(curl, CURLOPT_URL, url); switch(method) { case GET: break; case PUT: curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); break; case POST: curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); break; case DELETE: curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); break; default: ret = EINVAL; fprintf(stderr, "ERROR: Invalid HTTP method\n"); goto done; } if (followloc == YES) { curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); } /* Now run the curl handler */ curlCode = curl_easy_perform(curl); if (curlCode != CURLE_OK) { ret = EIO; fprintf(stderr, "ERROR: preform the URL %s failed, <%d>: %s\n", url, curlCode, curl_easy_strerror(curlCode)); } done: if (curl != NULL) { curl_easy_cleanup(curl); } if (ret) { free(resp); resp = NULL; } *response = resp; return ret; }
/** * The function does the write operation by connecting to a DataNode. * The function keeps the connection with the DataNode until * the closeFlag is set. Whenever the current data has been sent out, * the function blocks waiting for further input from user or close. * * @param url URL of the remote DataNode * @param method PUT for create and POST for append * @param uploadBuffer Buffer storing user's data to write * @param response Response from remote service * @return 0 for success and non-zero value to indicate error */ static int launchWrite(const char *url, enum HttpHeader method, struct webhdfsBuffer *uploadBuffer, struct Response **response) { CURLcode curlCode; struct Response* resp = NULL; struct curl_slist *chunk = NULL; CURL *curl = NULL; int ret = 0; if (!uploadBuffer) { fprintf(stderr, "ERROR: upload buffer is NULL!\n"); return EINVAL; } initCurlGlobal(); resp = calloc(1, sizeof(struct Response)); if (!resp) { return ENOMEM; } ret = initResponseBuffer(&(resp->body)); if (ret) { goto done; } ret = initResponseBuffer(&(resp->header)); if (ret) { goto done; } // Connect to the datanode in order to create the lease in the namenode curl = curl_easy_init(); if (!curl) { fprintf(stderr, "ERROR: failed to initialize the curl handle.\n"); return ENOMEM; } curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc); curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp->body); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, writefunc); curl_easy_setopt(curl, CURLOPT_WRITEHEADER, resp->header); curl_easy_setopt(curl, CURLOPT_READFUNCTION, readfunc); curl_easy_setopt(curl, CURLOPT_READDATA, uploadBuffer); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); chunk = curl_slist_append(chunk, "Transfer-Encoding: chunked"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); chunk = curl_slist_append(chunk, "Expect:"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); switch(method) { case PUT: curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); break; case POST: curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); break; default: ret = EINVAL; fprintf(stderr, "ERROR: Invalid HTTP method\n"); goto done; } curlCode = curl_easy_perform(curl); if (curlCode != CURLE_OK) { ret = EIO; fprintf(stderr, "ERROR: preform the URL %s failed, <%d>: %s\n", url, curlCode, curl_easy_strerror(curlCode)); } done: if (chunk != NULL) { curl_slist_free_all(chunk); } if (curl != NULL) { curl_easy_cleanup(curl); } if (ret) { free(resp); resp = NULL; } *response = resp; return ret; }
static int hdfsReadImpl(hdfsFS fs, hdfsFile file, void* buffer, tSize off, tSize length, tSize *numRead) { int ret = 0; char *url = NULL; struct Response *resp = NULL; if (fs == NULL || file == NULL || file->type != INPUT || buffer == NULL || length < 0) { ret = EINVAL; goto done; } if (length == 0) { // Special case: the user supplied a buffer of zero length, so there is // nothing to do. *numRead = 0; goto done; } resp = calloc(1, sizeof(*resp)); // resp is actually a pointer type if (!resp) { ret = ENOMEM; goto done; } ret = initResponseBuffer(&(resp->header)); if (ret) { goto done; } ret = initResponseBuffer(&(resp->body)); if (ret) { goto done; } memset(buffer, 0, length); resp->body->content = buffer; resp->body->remaining = length; ret = createUrlForOPEN(fs->nn, fs->port, file->file->absPath, fs->userName, off, length, &url); if (ret) { goto done; } ret = launchOPEN(url, resp); if (ret) { goto done; } ret = parseOPEN(resp->header->content, resp->body->content); if (ret == -1) { // Special case: if parseOPEN returns -1, we asked for a byte range // with outside what the file contains. In this case, hdfsRead and // hdfsPread return 0, meaning end-of-file. *numRead = 0; } else if (ret == 0) { *numRead = (tSize) resp->body->offset; } done: if (resp) { freeResponseBuffer(resp->header); free(resp->body); } free(resp); free(url); return ret; }