static int
ahc_echo (void *cls,
          struct MHD_Connection *connection,
          const char *url,
          const char *method,
          const char *version,
          const char *upload_data, size_t *upload_data_size, void **ptr)
{
  static int aptr;
  struct MHD_Response *response;
  int ret;

  if (0 != strcmp (method, "GET"))
    return MHD_NO;              /* unexpected method */
  if (&aptr != *ptr)
    {
      /* do never respond on first call */
      *ptr = &aptr;
      return MHD_YES;
    }
  *ptr = NULL;                  /* reset when done */
  response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
                                                1024,
                                                &callback,
                                                NULL,
                                                NULL);
  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  MHD_destroy_response (response);
  return ret;
}
static int
ahc_echo (void *cls,
          struct MHD_Connection *connection,
          const char *url,
          const char *method,
          const char *version,
          const char *upload_data, size_t *upload_data_size, void **ptr)
{
  static int aptr;
  const char *me = cls;
  struct MHD_Response *response;
  struct MHD_Response **responseptr;
  int ret;

  if (0 != strcmp (me, method))
    return MHD_NO;              /* unexpected method */
  if (&aptr != *ptr)
    {
      /* do never respond on first call */
      *ptr = &aptr;
      return MHD_YES;
    }
  responseptr = malloc (sizeof (struct MHD_Response *));
  response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
                                                1024,
                                                &crc, responseptr, &crcf);
  *responseptr = response;
  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  MHD_destroy_response (response);
  return ret;
}
static int
ahc_echo (void *cls,
          struct MHD_Connection *connection,
          const char *url,
          const char *method,
          const char *version,
          const char *upload_data, size_t *upload_data_size,
          void **unused)
{
  static int ptr;
  const char *me = cls;
  struct MHD_Response *response;
  int ret;

  //fprintf (stderr, "In CB: %s!\n", method);
  if (0 != strcmp (me, method))
    return MHD_NO;              /* unexpected method */
  if (&ptr != *unused)
    {
      *unused = &ptr;
      return MHD_YES;
    }
  *unused = NULL;
  response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 
						32 * 1024,
						&push_callback,
						&ok,
						&push_free_callback);
  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  MHD_destroy_response (response);
  if (ret == MHD_NO)
    abort ();
  return ret;
}
Example #4
0
int webu_stream_mjpeg(struct webui_ctx *webui) {
    /* Create the stream for the motion jpeg */
    int retcd;
    struct MHD_Response *response;

    if (webu_stream_checks(webui) == -1) return MHD_NO;

    webu_stream_cnct_count(webui);

    webu_stream_mjpeg_checkbuffers(webui);

    gettimeofday(&webui->time_last, NULL);

    response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 1024
        ,&webu_stream_mjpeg_response, webui, NULL);
    if (!response){
        MOTION_LOG(ERR, TYPE_STREAM, NO_ERRNO, _("Invalid response"));
        return MHD_NO;
    }

    if (webui->cnt->conf.stream_cors_header != NULL){
        MHD_add_response_header (response, MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN
            , webui->cnt->conf.stream_cors_header);
    }

    MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE
        , "multipart/x-mixed-replace; boundary=BoundaryString");

    retcd = MHD_queue_response (webui->connection, MHD_HTTP_OK, response);
    MHD_destroy_response (response);

    return retcd;
}
Example #5
0
    // return MHD_NO or MHD_YES
    virtual int handleRequest(  struct MHD_Connection *connection,
                                const char *url, const char */*method*/, const char */*version*/,
                                const char */*upload_data*/, size_t */*upload_data_size*/)
    {
        if(rsFiles == 0)
        {
            sendMessage(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Error: rsFiles is null. Retroshare is probably not yet started.");
            return MHD_YES;
        }
        if(url[0] == 0 || (mHash=RsFileHash(url+strlen(FILESTREAMER_ENTRY_PATH))).isNull())
        {
            sendMessage(connection, MHD_HTTP_NOT_FOUND, "Error: URL is not a valid file hash");
            return MHD_YES;
        }
        FileInfo info;
        std::list<RsFileHash> dls;
        rsFiles->FileDownloads(dls);
        if(!(rsFiles->alreadyHaveFile(mHash, info) || std::find(dls.begin(), dls.end(), mHash) != dls.end()))
        {
            sendMessage(connection, MHD_HTTP_NOT_FOUND, "Error: file not existing on local peer and not downloading. Start the download before streaming it.");
            return MHD_YES;
        }
        mSize = info.size;

        struct MHD_Response* resp = MHD_create_response_from_callback(
                    mSize, 1024*1024, &contentReadercallback, this, NULL);

        // only mp3 at the moment
        MHD_add_response_header(resp, "Content-Type", "audio/mpeg3");
        secure_queue_response(connection, MHD_HTTP_OK, resp);
        MHD_destroy_response(resp);
        return MHD_YES;
    }
Example #6
0
int file_request(
    void *cls,
    struct MHD_Connection *connection,
    const char *url,
    const char *method,
    const char *version,
    const char *upload_data,
    size_t *upload_data_size,
    void **con_cls)
{
  static int aptr;
  struct MHD_Response *response;
  int ret;
  FILE *file;
  struct stat buf;

  if (0 != strcmp(method, MHD_HTTP_METHOD_GET)) {
    return MHD_NO;              /* unexpected method */
  }
  if (&aptr != *con_cls) {
    /* do never respond on first call */
    *con_cls = &aptr;
    return MHD_YES;
  }
  *con_cls = NULL;                  /* reset when done */

  std::string surl(&url[1]);
  const char* filepath = (path + surl).c_str();

  if (0 == stat(filepath, &buf)) {
    file = fopen(filepath, "rb");
  } else {
    file = NULL;
  }
  if (file == NULL) {
    response = MHD_create_response_from_buffer(strlen(filepath),
        (void *)filepath,
        MHD_RESPMEM_PERSISTENT);
    ret = MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, response);
    MHD_destroy_response(response);
  } else {
    /* 32k page size */
    response = MHD_create_response_from_callback(
        buf.st_size,
        32 * 1024,
        &file_reader,
        file,
        &free_callback);
    if (response == NULL) {
      fclose(file);
      return MHD_NO;
    }
    ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
    MHD_destroy_response(response);
  }
  return ret;
}
Example #7
0
static int accept_connection(void           *cls,
                             MHD_Connection *connection,
                             const char     *url,
                             const char     *method,
                             const char     *version,
                             const char     *upload_data,
                             size_t         *upload_data_size,
                             void          **con_cls)
{
    if (strcmp(method, "POST") == 0) {
        ReadOperationBuilder *queryproc = static_cast<ReadOperationBuilder*>(cls);
        ReadOperation* cursor = static_cast<ReadOperation*>(*con_cls);

        if (cursor == nullptr) {
            cursor = queryproc->create();
            *con_cls = cursor;
            return MHD_YES;
        }
        if (*upload_data_size) {
            cursor->append(upload_data, *upload_data_size);
            *upload_data_size = 0;
            return MHD_YES;
        }

        auto error_response = [&](const char* msg) {
            char buffer[0x200];
            int len = snprintf(buffer, 0x200, "-%s\r\n", msg);
            auto response = MHD_create_response_from_buffer(len, buffer, MHD_RESPMEM_MUST_COPY);
            int ret = MHD_queue_response(connection, MHD_HTTP_BAD_REQUEST, response);
            MHD_destroy_response(response);
            return ret;
        };

        // Should be called once
        try {
            cursor->start();
        } catch (const std::exception& err) {
            return error_response(err.what());
        }

        // Check for error
        auto err = cursor->get_error();
        if (err != AKU_SUCCESS) {
            const char* error_msg = aku_error_message(err);
            return error_response(error_msg);
        }

        auto response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 64*1024, &read_callback, cursor, &free_callback);
        int ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
        MHD_destroy_response(response);
        return ret;
    } else {
        // Unsupported method
        // TODO: implement GET handler for simple queries (self diagnostics)
        return MHD_NO;
    }
}
static int
ahc_echo (void *cls,
          struct MHD_Connection *connection,
          const char *url,
          const char *method,
          const char *version,
          const char *upload_data,
	  size_t *upload_data_size, void **ptr)
{
  static int aptr;
  struct MHD_Response *response;
  int ret;
  FILE *file;
  struct stat buf;

  if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
    return MHD_NO;              /* unexpected method */
  if (&aptr != *ptr)
    {
      /* do never respond on first call */
      *ptr = &aptr;
      return MHD_YES;
    }
  *ptr = NULL;                  /* reset when done */
  if ( (0 == stat (&url[1], &buf)) &&
       (S_ISREG (buf.st_mode)) )
    file = fopen (&url[1], "rb");
  else
    file = NULL;
  if (file == NULL)
    {
      response = MHD_create_response_from_buffer (strlen (PAGE),
						  (void *) PAGE,
						  MHD_RESPMEM_PERSISTENT);
      ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response);
      MHD_destroy_response (response);
    }
  else
    {
      response = MHD_create_response_from_callback (buf.st_size, 32 * 1024,     /* 32k page size */
                                                    &file_reader,
                                                    file,
                                                    &free_callback);
      if (response == NULL)
	{
	  fclose (file);
	  return MHD_NO;
	}
      ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
      MHD_destroy_response (response);
    }
  return ret;
}
/**
 * Handles static content under /var/www. This handles checks for attempts by the client to gain access outside of
 * that directory, then hands the file to microhttpd to stream it back.
 * 
 * @param connection
 * @return 
 */
int staticHandler(struct MHD_Connection * connection, const char *url) {
    char *p;
    int l;
    struct stat buf;
    struct MHD_Response *response;
    FILE *file;

    // Validate url - i.e. must start with /
    if (url[0] != '/')
        return MHD_NO;

    // Validate url - cannot contain /. (also mean /.. as well)
    // This prevents people from scanning outside of /var/www using ../../ style url's
    p = findString((char *) url, (char *) INVALID);
    if (p)
        return MHD_NO;

    // Form the file path
    l = strlen(url) + strlen(BASE) + 1;
    p = (char *) malloc(l);
    if (!p)
        return MHD_NO;
    strcpy(p, BASE);
    strcat(p, url);

    // Do we have access?
    if (stat(p, &buf)) {
        free(p);
        return MHD_NO;
    }

    // Open the file, although the stat above should pass we could still fail here
    file = fopen(p, "rb");
    if (!file) {
        free(p);
        return MHD_NO;
    }

    // Hand the file to microhttpd to stream back to the client
    response = MHD_create_response_from_callback(buf.st_size, PAGE_SIZE, &file_reader, file, &free_callback);
    if (response == NULL) {
        free(p);
        fclose(file);
        return MHD_NO;
    }

    int ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
    MHD_destroy_response(response);

    // Cleanup
    free(p);
    return ret;
}
Example #10
0
static int
callback(void *cls, struct MHD_Connection *connection, const char *url,
	 const char *method, const char *version, const char *upload_data,
	 size_t *upload_data_size, void **con_cls) {
  struct callback_closure *cbc = calloc(1, sizeof(struct callback_closure));
  struct MHD_Response *r;

  r = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 1024, 
					 &called_twice, cbc, 
					 &free);
  MHD_queue_response(connection, 200, r);
  MHD_destroy_response(r);
  return MHD_YES;
}
Example #11
0
int test_http_server_send_half_handler(void * cls,
		    struct MHD_Connection * connection,
		    const char * url,
		    const char * method,
            const char * version,
		    const char * upload_data,
		    size_t * upload_data_size, 
    		void ** ptr) {

	test_http_server * handle = cls;
	struct MHD_Response * response;
	int ret;
	int * c_count;
	if (*ptr == NULL) {
		handle->log = apr_hash_make(handle->pool);
	  	/* The first time only the headers are valid,
		 do not respond in the first round... */
	  	*ptr = cls; //just to flag its not null....
	  	int * c_count = apr_palloc(handle->pool, sizeof(int));
		*c_count = 0;
		*ptr = c_count;
	  	return MHD_YES;
	}
	c_count = *ptr;
	if(*c_count == 0) {
		//log the request....
		apr_hash_set(handle->log,  apr_pstrdup(handle->pool, "METHOD"), APR_HASH_KEY_STRING, apr_pstrdup(handle->pool, method));
		apr_hash_set(handle->log,  apr_pstrdup(handle->pool, "URL"), APR_HASH_KEY_STRING, apr_pstrdup(handle->pool, url));
		apr_hash_set(handle->log,  apr_pstrdup(handle->pool, "VERSION"), APR_HASH_KEY_STRING, apr_pstrdup(handle->pool, version));
		apr_hash_set(handle->log,  apr_pstrdup(handle->pool, "DATA_LENGTH"), APR_HASH_KEY_STRING, apr_pmemdup (handle->pool, upload_data_size, sizeof(size_t)));
		apr_hash_set(handle->log,  apr_pstrdup(handle->pool, "DATA"), APR_HASH_KEY_STRING, apr_pmemdup (handle->pool, upload_data, *upload_data_size));
	}
	*c_count = *c_count+1;
	if(*upload_data_size == 0) {


		response = MHD_create_response_from_callback(strlen(handle->response), strlen(handle->response) / 10, test_http_server_send_half_response_handler, 
		                                             handle, test_http_server_send_half_response_free_handler);

		ret = MHD_queue_response(connection,
				   handle->response_code,
				   response);
		MHD_destroy_response(response);
		return ret;
	} else {
		*upload_data_size = 0; //we processed everything?
		return MHD_YES;
	}
}
Example #12
0
/**
 * Create a response object.  The response object can be extended with
 * header information and then be used any number of times.
 *
 * @param size size of the data portion of the response
 * @param fd file descriptor referring to a file on disk with the data
 * @return NULL on error (i.e. invalid arguments, out of memory)
 */
struct MHD_Response *MHD_create_response_from_fd (size_t size,
        int fd)
{
    struct MHD_Response *ret;

    ret = MHD_create_response_from_callback (size,
            4 * 1024,
            &file_reader,
            NULL,
            &free_callback);
    if (ret == NULL)
        return NULL;
    ret->fd = fd;
    ret->crc_cls = ret;
    return ret;
}
Example #13
0
void http_response::get_raw_response_deferred(
        MHD_Response** response,
        webserver* ws
)
{
    if(!completed)
        *response = MHD_create_response_from_callback(
                MHD_SIZE_UNKNOWN,
                1024,
                &details::cb,
                this,
                NULL
        );
    else
        static_cast<http_response*>(this)->get_raw_response(response, ws);
}
Example #14
0
void http_response::get_raw_response_lp_receive(
        MHD_Response** response,
        webserver* ws
)
{
    this->ws = ws;
    this->connection_id = this->underlying_connection;

    *response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 80,
        &http_response::data_generator, (void*) this, NULL);

    ws->register_to_topics(
            topics,
            connection_id
    );
}
Example #15
0
void RESTRequestState::set_callback_response(RESTContentReaderCallback rsp_writer, const char* content_type)
{
	const char* accept_enc = MHD_lookup_connection_value(get_conn(), MHD_HEADER_KIND, "Accept-Encoding");
	bool use_gzip = accept_enc && strstr(accept_enc, "gzip");

	set_response(MHD_create_response_from_callback(
			-1, RESPONSE_BLOCK_SIZE,
			callback_write,
			new ContentReaderState(rsp_writer, get_free_callback(), get_callback_data(), use_gzip),
			callback_free));
	MHD_add_response_header(get_response(), "Content-Type", content_type);
	if (use_gzip)
		MHD_add_response_header(get_response(), "Content-Encoding", "gzip");

	/* libmicrohttpd will call the appropriate callback to free the data instead of us */
	set_free_callback(NULL);
}
Example #16
0
static int
ahc_echo (void *cls,
          struct MHD_Connection *connection,
          const char *url,
          const char *method,
          const char *upload_data,
          const char *version, unsigned int *upload_data_size, void **ptr)
{
  static int aptr;
  struct MHD_Response *response;
  int ret;
  FILE *file;
  struct stat buf;

  if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
    return MHD_NO;              /* unexpected method */
  if (&aptr != *ptr)
    {
      /* do never respond on first call */
      *ptr = &aptr;
      return MHD_YES;
    }
  *ptr = NULL;                  /* reset when done */
  file = fopen (&url[1], "r");
  if (file == NULL)
    {
      response = MHD_create_response_from_data (strlen (PAGE),
                                                (void *) PAGE,
                                                MHD_NO, MHD_NO);
      ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response);
      MHD_destroy_response (response);
    }
  else
    {
      stat (&url[1], &buf);
      response = MHD_create_response_from_callback (buf.st_size, 32 * 1024,     /* 32k page size */
                                                    &file_reader,
                                                    file,
                                                    (MHD_ContentReaderFreeCallback)
                                                    & fclose);
      ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
      MHD_destroy_response (response);
    }
  return ret;
}
/*
 * web_send_file
 * Read files and send them out
 */
int web_send_file (struct MHD_Connection *conn, const char *filename, const int code, const bool unl)
{
	struct stat buf;
	FILE *fp;
	struct MHD_Response *response;
	const char *p;
	const char *ct = NULL;
	int ret;

	if ((p = strchr(filename, '.')) != NULL) {
		p++;
		if (strcmp(p, "xml") == 0)
			ct = "text/xml";
		else if (strcmp(p, "js") == 0)
			ct = "text/javascript";
	}
	if (stat(filename, &buf) == -1 ||
			((fp = fopen(filename, "r")) == NULL)) {
		if (strcmp(p, "xml") == 0)
			response = MHD_create_response_from_data(0, (void *)"", MHD_NO, MHD_NO);
		else {
			int len = strlen(FNF) + strlen(filename) - 1; // len(%s) + 1 for \0
			char *s = (char *)malloc(len);
			if (s == NULL) {
				fprintf(stderr, "Out of memory FNF\n");
				exit(1);
			}
			snprintf(s, len, FNF, filename);
			response = MHD_create_response_from_data(len, (void *)s, MHD_YES, MHD_NO); // free
		}
	} else
		response = MHD_create_response_from_callback(buf.st_size, 32 * 1024, &web_read_file, fp,
				&web_close_file);
	if (response == NULL)
		return MHD_YES;
	if (ct != NULL)
		MHD_add_response_header(response, "Content-type", ct);
	ret = MHD_queue_response(conn, code, response);
	MHD_destroy_response(response);
	if (unl)
		unlink(filename);
	return ret;
}
Example #18
0
/**
 * Create a response object.  The response object can be extended with
 * header information and then be used any number of times.
 *
 * @param size size of the data portion of the response
 * @param fd file descriptor referring to a file on disk with the
 *        data; will be closed when response is destroyed;
 *        fd should be in 'blocking' mode
 * @param offset offset to start reading from in the file;
 *        Be careful! `off_t` may have been compiled to be a
 *        64-bit variable for MHD, in which case your application
 *        also has to be compiled using the same options! Read
 *        the MHD manual for more details.
 * @return NULL on error (i.e. invalid arguments, out of memory)
 * @ingroup response
 */
struct MHD_Response *
MHD_create_response_from_fd_at_offset (size_t size,
				       int fd,
				       off_t offset)
{
  struct MHD_Response *response;

  response = MHD_create_response_from_callback (size,
						4 * 1024,
						&file_reader,
						NULL,
						&free_callback);
  if (NULL == response)
    return NULL;
  response->fd = fd;
  response->fd_off = offset;
  response->crc_cls = response;
  return response;
}
Example #19
0
void http_response::get_raw_response_lp_receive(
        MHD_Response** response,
        webserver* ws
)
{
    this->ws = ws;
    this->connection_id = MHD_get_connection_info(
            this->underlying_connection,
            MHD_CONNECTION_INFO_CLIENT_ADDRESS
    )->client_addr;

    *response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 80,
        &http_response::data_generator, (void*) this, NULL);

    ws->register_to_topics(
            topics,
            connection_id,
            keepalive_secs,
            keepalive_msg
    );
}
Example #20
0
int CWebServer::CreateFileDownloadResponse(IHTTPRequestHandler *handler, struct MHD_Response *&response)
{
  if (handler == NULL)
    return MHD_NO;

  const HTTPRequest &request = handler->GetRequest();
  const HTTPResponseDetails &responseDetails = handler->GetResponseDetails();
  HttpResponseRanges responseRanges = handler->GetResponseData();

  std::shared_ptr<XFILE::CFile> file = std::make_shared<XFILE::CFile>();
  std::string filePath = handler->GetResponseFile();

  if (!file->Open(filePath, READ_NO_CACHE))
  {
    CLog::Log(LOGERROR, "WebServer: Failed to open %s", filePath.c_str());
    return SendErrorResponse(request.connection, MHD_HTTP_NOT_FOUND, request.method);
  }

  bool ranged = false;
  uint64_t fileLength = static_cast<uint64_t>(file->GetLength());

  // get the MIME type for the Content-Type header
  std::string mimeType = responseDetails.contentType;
  if (mimeType.empty())
  {
    std::string ext = URIUtils::GetExtension(filePath);
    StringUtils::ToLower(ext);
    mimeType = CreateMimeTypeFromExtension(ext.c_str());
  }

  if (request.method != HEAD)
  {
    uint64_t totalLength = 0;
    std::unique_ptr<HttpFileDownloadContext> context(new HttpFileDownloadContext());
    context->file = file;
    context->contentType = mimeType;
    context->boundaryWritten = false;
    context->writePosition = 0;

    if (handler->IsRequestRanged())
    {
      if (!request.ranges.IsEmpty())
        context->ranges = request.ranges;
      else
        GetRequestedRanges(request.connection, fileLength, context->ranges);
    }

    uint64_t firstPosition = 0;
    uint64_t lastPosition = 0;
    // if there are no ranges, add the whole range
    if (context->ranges.IsEmpty())
      context->ranges.Add(CHttpRange(0, fileLength - 1));
    else
    {
      handler->SetResponseStatus(MHD_HTTP_PARTIAL_CONTENT);

      // we need to remember that we are ranged because the range length might change and won't be reliable anymore for length comparisons
      ranged = true;

      context->ranges.GetFirstPosition(firstPosition);
      context->ranges.GetLastPosition(lastPosition);
    }

    // remember the total number of ranges
    context->rangeCountTotal = context->ranges.Size();
    // remember the total length
    totalLength = context->ranges.GetLength();

    // adjust the MIME type and range length in case of multiple ranges which requires multipart boundaries
    if (context->rangeCountTotal > 1)
    {
      context->boundary = HttpRangeUtils::GenerateMultipartBoundary();
      mimeType = HttpRangeUtils::GenerateMultipartBoundaryContentType(context->boundary);

      // build part of the boundary with the optional Content-Type header
      // "--<boundary>\r\nContent-Type: <content-type>\r\n
      context->boundaryWithHeader = HttpRangeUtils::GenerateMultipartBoundaryWithHeader(context->boundary, context->contentType);
      context->boundaryEnd = HttpRangeUtils::GenerateMultipartBoundaryEnd(context->boundary);

      // for every range, we need to add a boundary with header
      for (HttpRanges::const_iterator range = context->ranges.Begin(); range != context->ranges.End(); ++range)
      {
        // we need to temporarily add the Content-Range header to the boundary to be able to determine the length
        std::string completeBoundaryWithHeader = HttpRangeUtils::GenerateMultipartBoundaryWithHeader(context->boundaryWithHeader, &*range);
        totalLength += completeBoundaryWithHeader.size();

        // add a newline before any new multipart boundary
        if (range != context->ranges.Begin())
          totalLength += strlen(HEADER_NEWLINE);
      }
      // and at the very end a special end-boundary "\r\n--<boundary>--"
      totalLength += context->boundaryEnd.size();
    }

    // set the initial write position
    context->ranges.GetFirstPosition(context->writePosition);

    // create the response object
    response = MHD_create_response_from_callback(totalLength, 2048,
                                                  &CWebServer::ContentReaderCallback,
                                                  context.get(),
                                                  &CWebServer::ContentReaderFreeCallback);
    if (response == NULL)
    {
      CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP response for %s to be filled from %s", request.pathUrl.c_str(), filePath.c_str());
      return MHD_NO;
    }

    context.release(); // ownership was passed to mhd

    // add Content-Range header
    if (ranged)
      handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_RANGE, HttpRangeUtils::GenerateContentRangeHeaderValue(firstPosition, lastPosition, fileLength));
  }
  else
  {
    response = MHD_create_response_from_data(0, NULL, MHD_NO, MHD_NO);
    if (response == NULL)
    {
      CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP HEAD response for %s", request.pathUrl.c_str());
      return MHD_NO;
    }

    handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_LENGTH, StringUtils::Format("%" PRId64, fileLength));
  }

  // set the Content-Type header
  if (!mimeType.empty())
    handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_TYPE, mimeType);

  return MHD_YES;
}
static int
ahc_echo (void *cls,
          struct MHD_Connection *connection,
          const char *url,
          const char *method,
          const char *version,
          const char *upload_data,
	  size_t *upload_data_size, void **ptr)
{
  static int aptr;
  struct MHD_Response *response;
  int ret;
  FILE *file;
  DIR *dir;
  struct stat buf;
  char emsg[1024];

  if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
    return MHD_NO;              /* unexpected method */
  if (&aptr != *ptr)
    {
      /* do never respond on first call */
      *ptr = &aptr;
      return MHD_YES;
    }
  *ptr = NULL;                  /* reset when done */
  if ( (0 == stat (&url[1], &buf)) &&
       (S_ISREG (buf.st_mode)) )
    file = fopen (&url[1], "rb");
  else
    file = NULL;
  if (file == NULL)
    {
      dir = opendir (".");
      if (dir == NULL)
	{
	  /* most likely cause: more concurrent requests than  
	     available file descriptors / 2 */
	  snprintf (emsg,
		    sizeof (emsg),
		    "Failed to open directory `.': %s\n",
		    strerror (errno));
	  response = MHD_create_response_from_buffer (strlen (emsg),
						      emsg,
						      MHD_RESPMEM_MUST_COPY);
	  if (response == NULL)
	    return MHD_NO;	    
	  ret = MHD_queue_response (connection, MHD_HTTP_SERVICE_UNAVAILABLE, response);
	  MHD_destroy_response (response);
	}
      else
	{
	  response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
							32 * 1024,
							&dir_reader,
							dir,
							&dir_free_callback);
	  if (response == NULL)
	    {
	      closedir (dir);
	      return MHD_NO;
	    }
	  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
	  MHD_destroy_response (response);
	}
    }
  else
    {
      response = MHD_create_response_from_callback (buf.st_size, 32 * 1024,     /* 32k page size */
                                                    &file_reader,
                                                    file,
                                                    &file_free_callback);
      if (response == NULL)
	{
	  fclose (file);
	  return MHD_NO;
	}
      ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
      MHD_destroy_response (response);
    }
  return ret;
}
Example #22
0
static int OnHttpRequest(void* cls,
                         struct MHD_Connection* connection,
                         const char* url,
                         const char* method,
                         const char* version,
                         const char* upload_data,
                         size_t* upload_data_size,
                         void** ptr)
{
  if (!*ptr)
  {
    *ptr = new std::string;
    return MHD_YES;
  }

  std::string* str = (std::string*) *ptr;

  if (strcmp(method, "POST") == 0 && *upload_data_size)
  {
    *upload_data_size = 0;
    (*str) += upload_data;
    return MHD_YES;
  }

  CLog::Log(LOGDEBUG,"OnHttpRequest - enter function [url=%s][method=%s][version=%s][upload_data=%s][upload_data_size=%lu] (hsrv)",url,method,version,upload_data,*upload_data_size);

  CHttpServer* httpServer = (CHttpServer*)cls;
  if (!httpServer)
  {
    CLog::Log(LOGERROR,"OnHttpRequest - FAILED to get server context (hsrv)");
    return MHD_NO;
  }

  MAPHTTPHEADER header;
  MHD_get_connection_values(connection, MHD_HEADER_KIND, HeadersIterator, &header);

#if 0
  std::map<char*, char*>::const_iterator end = headerParams.end();
  for (std::map<char*, char*>::const_iterator it = headerParams.begin(); it != end; ++it)
  {
      std::cout << "Key: " << it->first;
      std::cout << "Value: " << it->second << '\n';
  }
#endif

  CHttpRequest httpRequest((char*) method, (char*) version, (char*) url, header, str->size(), (char*) str->c_str());
  CHttpResponse httpResponse;

  CLog::Log(LOGDEBUG,"OnHttpRequest - BEFORE HandleRequest with [method=%s][version=%s][url=%s][str=%s][strSize=%lu] (hsrv)",method,version,url,str->c_str(),str->size());
  httpServer->HandleRequest(httpRequest, httpResponse);
  CLog::Log(LOGDEBUG,"OnHttpRequest - AFTER HandleRequest with [method=%s][version=%s][url=%s][str=%s][strSize=%lu]. [IsChunked=%d] (hsrv)",method,version,url,str->c_str(),str->size(),httpResponse.IsChunked());

  struct MHD_Response* response;

  if (httpResponse.IsChunked())
  {
    CStdString deviceId = "";
    IMAPHTTPHEADER it = header.find("X-Boxee-Device-ID");
    if (it == header.end())
    {
      CLog::Log(LOGWARNING,"OnHttpRequest - FAILED to get X-Boxee-Device-ID from header for chunked request (hsrv)");
    }
    else
    {
      deviceId = it->second;
    }

    CReaderCallback* readerCls = new CReaderCallback(deviceId, CStdString(url));
    readerCls->chunkedCB = httpResponse.GetChunkedCallback();

    CLog::Log(LOGDEBUG,"OnHttpRequest - going to response_from_callback. [method=%s][version=%s][url=%s][str=%s][strSize=%lu]. [IsChunked=%d] (hsrv)",method,version,url,str->c_str(),str->size(),httpResponse.IsChunked());

    response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 65535, readerCallback, readerCls, NULL);

    if (MHD_add_response_header(response, "Transfer-Encoding", "chunked") == MHD_NO)
    {
      CLog::Log(LOGERROR,"OnHttpRequest - FAILED to add server to header");
      return MHD_NO;
    }
  }
  else
  {
    unsigned char* bodyPtr = &(httpResponse.GetBody()[0]);
    response = MHD_create_response_from_buffer(httpResponse.GetBody().size(), bodyPtr, MHD_RESPMEM_MUST_COPY);
  }

  if (!response)
  {
    CLog::Log(LOGERROR,"OnHttpRequest - FAILED to create response. [%s] (hsrv)",method);
    return MHD_NO;
  }

  if (MHD_add_response_header(response, "Server", httpServer->GetServerAgent().c_str()) == MHD_NO)
  {
    CLog::Log(LOGERROR,"OnHttpRequest - FAILED to add server to header");
    return MHD_NO;
  }

  std::map<std::string, std::string>::iterator it = httpResponse.GetHeader().begin();
  while (it != httpResponse.GetHeader().end())
  {
    if (MHD_add_response_header(response, it->first.c_str(), it->second.c_str()) == MHD_NO)
    {
      CLog::Log(LOGERROR,"OnHttpRequest - FAILED to add response header [%s=%s] (hsrv)", it->first.c_str(), it->second.c_str());
    }

    it++;
  }

  CLog::Log(LOGDEBUG,"OnHttpRequest - going to queue response. [code=%d][bodySize=%lu] (hsrv)",httpResponse.GetCode(), httpResponse.GetBody().size());

  int retVal = MHD_YES;
  if (MHD_queue_response(connection, httpResponse.GetCode(), response) != MHD_YES)
  {
    CLog::Log(LOGERROR,"OnHttpRequest - FAILED to queue response. [%s] (hsrv)",method);
    retVal = MHD_NO;
  }

  MHD_destroy_response(response);

  delete str;

  return retVal;
}
Example #23
0
int answer_to_connection (void *cls, struct MHD_Connection *connection,
		const char *url, const char *method,
		const char *version, const char *upload_data,
		size_t *upload_data_size, void **con_cls)
{
	str page = {NULL, 0};
	struct MHD_Response *response;
	int ret;
	void *async_data = NULL;
	struct httpd_cb *cb;
	const char *normalised_url;
	struct post_request *pr;
	str_str_t *kv;
	char *p;
	int cnt_type = HTTPD_STD_CNT_TYPE;
	int accept_type = HTTPD_STD_CNT_TYPE;
	int ret_code = MHD_HTTP_OK;

	LM_DBG("START *** cls=%p, connection=%p, url=%s, method=%s, "
			"versio=%s, upload_data[%zu]=%p, *con_cls=%p\n",
			cls, connection, url, method, version,
			*upload_data_size, upload_data, *con_cls);

	pr = *con_cls;
	if(pr == NULL){
		pr = pkg_malloc(sizeof(struct post_request));
		if(pr==NULL) {
			LM_ERR("oom while allocating post_request structure\n");
			return MHD_NO;
		}
		memset(pr, 0, sizeof(struct post_request));
		*con_cls = pr;
		pr = NULL;
	}

	if(strncmp(method, "POST", 4)==0) {
		if(pr == NULL){
			pr = *con_cls;
			pr->p_list = slinkedl_init(&httpd_alloc, &httpd_free);
			if (pr->p_list==NULL) {
				LM_ERR("oom while allocating list\n");
				return MHD_NO;
			}
			LM_DBG("running MHD_create_post_processor\n");
			pr->pp = MHD_create_post_processor(connection,
											post_buf_size,
											&post_iterator,
											pr);
			if(pr->pp==NULL) {
				if (*upload_data_size == 0) {
					/* We need to wait for morte data before
					 * handling the POST request */
					return MHD_YES;
				}
				LM_DBG("NOT a regular POST :o)\n");
				if (pr->content_type==0 && pr->content_len==0)
					MHD_get_connection_values(connection, MHD_HEADER_KIND,
											&getConnectionHeader, pr);
				if (pr->content_type<=0 || pr->content_len<=0) {
					LM_ERR("got a bogus request\n");
					return MHD_NO;
				}
				if (*upload_data_size != pr->content_len) {
					/* For now, we don't support large POST with truncated data */
					LM_ERR("got a truncated POST request\n");
					return MHD_NO;
				}
				LM_DBG("got ContentType [%d] with len [%d]: %.*s\\n",
					pr->content_type, pr->content_len,
					(int)*upload_data_size, upload_data);
				/* Here we save data. */
				switch (pr->content_type) {
				case HTTPD_TEXT_XML_CNT_TYPE:
				case HTTPD_APPLICATION_JSON_CNT_TYPE:
					/* Save the entire body as 'body' */
					kv = (str_str_t*)slinkedl_append(pr->p_list,
							sizeof(str_str_t) + 1 +
							*upload_data_size);
					p = (char*)(kv + 1);
					kv->key.len = 1; kv->key.s = p;
					memcpy(p, "1", 1);
					p += 1;
					kv->val.len = *upload_data_size;
					kv->val.s = p;
					memcpy(p, upload_data, *upload_data_size);
					break;
				default:
					LM_ERR("Unhandled data for ContentType [%d]\n",
							pr->content_type);
					return MHD_NO;
				}
				/* Mark the fact that we consumed all data */
				*upload_data_size = 0;
				return MHD_YES;
			}

			LM_DBG("pr=[%p] pp=[%p] p_list=[%p]\n",
					pr, pr->pp, pr->p_list);
			return MHD_YES;
		} else {
			if (pr->pp==NULL) {
				if (*upload_data_size == 0) {
					if (pr->content_type==HTTPD_TEXT_XML_CNT_TYPE)
						cnt_type = HTTPD_TEXT_XML_CNT_TYPE;
					if (pr->content_type==HTTPD_APPLICATION_JSON_CNT_TYPE)
						cnt_type = HTTPD_APPLICATION_JSON_CNT_TYPE;
					*con_cls = pr->p_list;
					cb = get_httpd_cb(url);
					if (cb) {
						normalised_url = &url[cb->http_root->len+1];
						LM_DBG("normalised_url=[%s]\n", normalised_url);
						ret_code = cb->callback(cls, (void*)connection,
								normalised_url,
								method, version,
								upload_data, upload_data_size, con_cls,
								&buffer, &page);
					} else {
						page = MI_HTTP_U_URL;
						ret_code = MHD_HTTP_BAD_REQUEST;
					}
					/* slinkedl_traverse(pr->p_list,
							&httpd_print_data, NULL, NULL); */
					slinkedl_list_destroy(*con_cls);
					pkg_free(pr); *con_cls = pr = NULL;
					goto send_response;
				}
				LM_DBG("NOT a regular POST :o)\n");
				if (pr->content_type==0 && pr->content_len==0)
					MHD_get_connection_values(connection, MHD_HEADER_KIND,
											&getConnectionHeader, pr);
				if (pr->content_type<=0 || pr->content_len<=0) {
					LM_ERR("got a bogus request\n");
					return MHD_NO;
				}
				if (*upload_data_size != pr->content_len) {
					/* For now, we don't support large POST with truncated data */
					LM_ERR("got a truncated POST request\n");
					return MHD_NO;
				}
				LM_DBG("got ContentType [%d] with len [%d]: %.*s\\n",
					pr->content_type, pr->content_len,
					(int)*upload_data_size, upload_data);
				/* Here we save data. */
				switch (pr->content_type) {
				case HTTPD_TEXT_XML_CNT_TYPE:
				case HTTPD_APPLICATION_JSON_CNT_TYPE:
					/* Save the entire body as 'body' */
					kv = (str_str_t*)slinkedl_append(pr->p_list,
							sizeof(str_str_t) + 1 +
							*upload_data_size);
					p = (char*)(kv + 1);
					kv->key.len = 1; kv->key.s = p;
					memcpy(p, "1", 1);
					p += 1;
					kv->val.len = *upload_data_size;
					kv->val.s = p;
					memcpy(p, upload_data, *upload_data_size);
					break;
				default:
					LM_ERR("Unhandled data for ContentType [%d]\n",
							pr->content_type);
					return MHD_NO;
				}
				/* Mark the fact that we consumed all data */
				*upload_data_size = 0;
				return MHD_YES;
			}
			LM_DBG("running MHD_post_process: "
					"pp=%p status=%d upload_data_size=%zu\n",
					pr->pp, pr->status, *upload_data_size);
			if (pr->status<0) {
				slinkedl_list_destroy(pr->p_list);
				pr->p_list = NULL;
				/* FIXME:
				 * It might be better to reply with an error
				 * instead of resetting the connection via MHD_NO */
				return MHD_NO;
			}
			ret =MHD_post_process(pr->pp, upload_data, *upload_data_size);
			LM_DBG("ret=%d upload_data_size=%zu\n", ret, *upload_data_size);
			if(*upload_data_size != 0) {
				*upload_data_size = 0;
				return MHD_YES;
			}

			LM_DBG("running MHD_destroy_post_processor: "
					"pr=[%p] pp=[%p] p_list=[%p]\n",
					pr, pr->pp, pr->p_list);
			MHD_destroy_post_processor(pr->pp);
			LM_DBG("done MHD_destroy_post_processor\n");
			/* slinkedl_traverse(pr->p_list, &httpd_print_data, NULL, NULL); */
			*con_cls = pr->p_list;

			cb = get_httpd_cb(url);
			if (cb) {
				normalised_url = &url[cb->http_root->len+1];
				LM_DBG("normalised_url=[%s]\n", normalised_url);
				ret_code = cb->callback(cls, (void*)connection,
						normalised_url,
						method, version,
						upload_data, upload_data_size, con_cls,
						&buffer, &page);
			} else {
				page = MI_HTTP_U_URL;
				ret_code = MHD_HTTP_BAD_REQUEST;
			}
			/* slinkedl_traverse(pr->p_list, &httpd_print_data, NULL, NULL); */
			slinkedl_list_destroy(*con_cls);
			pkg_free(pr); *con_cls = pr = NULL;
		}
	}else if(strncmp(method, "GET", 3)==0) {
		pr = *con_cls;
		MHD_get_connection_values(connection, MHD_HEADER_KIND,
								&getConnectionHeader, pr);
		accept_type = pr->accept_type;
		pkg_free(pr); *con_cls = pr = NULL;
		LM_DBG("accept_type=[%d]\n", accept_type);
		cb = get_httpd_cb(url);
		if (cb) {
			normalised_url = &url[cb->http_root->len+1];
			LM_DBG("normalised_url=[%s]\n", normalised_url);
			ret_code = cb->callback(cls, (void*)connection,
					normalised_url,
					method, version,
					upload_data, upload_data_size, con_cls,
					&buffer, &page);
		} else {
			page = MI_HTTP_U_URL;
			ret_code = MHD_HTTP_BAD_REQUEST;
		}
	}else{
		page = MI_HTTP_U_METHOD;
		ret_code = MHD_HTTP_METHOD_NOT_ACCEPTABLE;
	}

send_response:
	if (page.s) {
		LM_DBG("MHD_create_response_from_data [%p:%d]\n",
			page.s, page.len);
		response = MHD_create_response_from_data(page.len,
							(void*)page.s,
							0, 1);
	} else {
		LM_DBG("MHD_create_response_from_callback\n");
		response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
							buffer.len,
							cb->flush_data_callback,
							(void*)async_data,
							NULL);
	}
	if (cnt_type==HTTPD_TEXT_XML_CNT_TYPE || accept_type==HTTPD_TEXT_XML_CNT_TYPE)
		MHD_add_response_header(response,
								MHD_HTTP_HEADER_CONTENT_TYPE,
								"text/xml; charset=utf-8");
	if (cnt_type==HTTPD_APPLICATION_JSON_CNT_TYPE || accept_type==HTTPD_APPLICATION_JSON_CNT_TYPE)
		MHD_add_response_header(response,
								MHD_HTTP_HEADER_CONTENT_TYPE,
								"application/json");
	ret = MHD_queue_response (connection, ret_code, response);
	MHD_destroy_response (response);

	return ret;
}
Example #24
0
int
http_cb_request (void *cls,
                struct MHD_Connection *connection,
                const char *url,
                const char *method,
                const char *version,
                const char *upload_data,
                size_t *upload_data_size,
                void **ptr)
{
  (void)cls;
  (void)url;
  (void)upload_data;
  (void)upload_data_size;
  
  int ret;
  struct Proxy *proxy;
  struct SPDY_Headers spdy_headers;
  bool with_body = false;
  struct HTTP_URI *http_uri;
  const char *header_value;

  if (NULL == ptr || NULL == *ptr)
    return MHD_NO;
    
  http_uri = (struct HTTP_URI *)*ptr;
    
  if(NULL == http_uri->proxy)
  {
    //first call for this request
    if (0 != strcmp (method, MHD_HTTP_METHOD_GET) && 0 != strcmp (method, MHD_HTTP_METHOD_POST))
    {
      free(http_uri->uri);
      free(http_uri);
      PRINT_INFO2("unexpected method %s", method);
      return MHD_NO;
    }
    
    if(NULL == (proxy = au_malloc(sizeof(struct Proxy))))
    {
      free(http_uri->uri);
      free(http_uri);
      PRINT_INFO("No memory");
      return MHD_NO; 
    }
    
    ++glob_opt.responses_pending;
    proxy->id = rand();
    proxy->http_active = true;
    proxy->http_connection = connection;
    http_uri->proxy = proxy;
    return MHD_YES;
  }
  
  proxy = http_uri->proxy;
  
  if(proxy->spdy_error || proxy->http_error)
    return MHD_NO; // handled at different place TODO? leaks?

  if(proxy->spdy_active)
  {
    if(0 == strcmp (method, MHD_HTTP_METHOD_POST))
    {
      PRINT_INFO("POST processing");
        
      int rc= spdylay_session_resume_data(proxy->spdy_connection->session, proxy->stream_id);
      PRINT_INFO2("rc is %i stream is %i", rc, proxy->stream_id);
      proxy->spdy_connection->want_io |= WANT_WRITE;
      
      if(0 == *upload_data_size)
      {
      PRINT_INFO("POST http EOF");
        proxy->receiving_done = true;
        return MHD_YES;
      }
      
      if(!copy_buffer(upload_data, *upload_data_size, &proxy->received_body, &proxy->received_body_size))
      {
        //TODO handle it better?
        PRINT_INFO("not enough memory (malloc/realloc returned NULL)");
        return MHD_NO;
      }
      
      *upload_data_size = 0;
                               
      return MHD_YES;
    }
  
    //already handled
    PRINT_INFO("unnecessary call to http_cb_request");
    return MHD_YES;
  }
  
  //second call for this request

  PRINT_INFO2("received request for '%s %s %s'", method, http_uri->uri, version);

  proxy->url = http_uri->uri;
  
  header_value = MHD_lookup_connection_value(connection,
    MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_LENGTH);
  
  with_body = 0 == strcmp (method, MHD_HTTP_METHOD_POST)
    && (NULL == header_value || 0 != strcmp ("0", header_value));
    
  PRINT_INFO2("body will be sent %i", with_body);
    
  ret = parse_uri(&glob_opt.uri_preg, proxy->url, &proxy->uri);
  if(ret != 0)
    DIE("parse_uri failed");
  proxy->http_uri = http_uri;

  spdy_headers.num = MHD_get_connection_values (connection,
                       MHD_HEADER_KIND,
                       NULL,
                       NULL);
  if(NULL == (spdy_headers.nv = au_malloc(((spdy_headers.num + 5) * 2 + 1) * sizeof(char *))))
    DIE("no memory");
  spdy_headers.nv[0] = ":method";     spdy_headers.nv[1] = method;
  spdy_headers.nv[2] = ":path";       spdy_headers.nv[3] = proxy->uri->path_and_more;
  spdy_headers.nv[4] = ":version";    spdy_headers.nv[5] = (char *)version;
  spdy_headers.nv[6] = ":scheme";     spdy_headers.nv[7] = proxy->uri->scheme;
  spdy_headers.nv[8] = ":host";       spdy_headers.nv[9] = NULL;
  //nv[14] = NULL;
  spdy_headers.cnt = 10;
  MHD_get_connection_values (connection,
                       MHD_HEADER_KIND,
                       &http_cb_iterate,
                       &spdy_headers);
                       
  spdy_headers.nv[spdy_headers.cnt] = NULL;
  if(NULL == spdy_headers.nv[9])
    spdy_headers.nv[9] = proxy->uri->host_and_port;

  if(0 != spdy_request(spdy_headers.nv, proxy, with_body))
  {
    free(spdy_headers.nv);
    //free_proxy(proxy);
    
    return MHD_NO;
  }
  free(spdy_headers.nv);
  
  proxy->http_response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
                         4096,
                         &http_cb_response,
                         proxy,
                         &http_cb_response_done);

  if (NULL == proxy->http_response)
    DIE("no response");
  
  if(MHD_NO == MHD_add_response_header (proxy->http_response,
                 "Proxy-Connection", "keep-alive"))
    PRINT_INFO("SPDY_name_value_add failed: ");
  if(MHD_NO == MHD_add_response_header (proxy->http_response,
                 "Connection", "Keep-Alive"))
    PRINT_INFO("SPDY_name_value_add failed: ");
  if(MHD_NO == MHD_add_response_header (proxy->http_response,
                 "Keep-Alive", "timeout=5, max=100"))
    PRINT_INFO("SPDY_name_value_add failed: ");
    
  proxy->spdy_active = true;
  
  return MHD_YES;
}