Esempio n. 1
0
static const char *test_should_keep_alive(void) {
  struct mg_connection conn;
  char req1[] = "GET / HTTP/1.1\r\n\r\n";
  char req2[] = "GET / HTTP/1.0\r\n\r\n";
  char req3[] = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n";
  char req4[] = "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n";

  memset(&conn, 0, sizeof(conn));
  ASSERT(parse_http_message(req1, sizeof(req1) - 1, &conn) == sizeof(req1) - 1);
  ASSERT(should_keep_alive(&conn) != 0);

  parse_http_message(req2, sizeof(req2) - 1, &conn);
  ASSERT(should_keep_alive(&conn) == 0);

  parse_http_message(req3, sizeof(req3) - 1, &conn);
  ASSERT(should_keep_alive(&conn) == 0);

  parse_http_message(req4, sizeof(req4) - 1, &conn);
  ASSERT(should_keep_alive(&conn) != 0);

  return NULL;
}
Esempio n. 2
0
END_TEST


START_TEST(test_should_keep_alive)
{
	/* Adapted from unit_test.c */
	/* Copyright (c) 2013-2015 the Civetweb developers */
	/* Copyright (c) 2004-2013 Sergey Lyubka */
	struct mg_connection conn;
	struct mg_context ctx;
	char req1[] = "GET / HTTP/1.1\r\n\r\n";
	char req2[] = "GET / HTTP/1.0\r\n\r\n";
	char req3[] = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n";
	char req4[] = "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n";
	char yes[] = "yes";
	char no[] = "no";

	memset(&conn, 0, sizeof(conn));
	conn.ctx = &ctx;
	ck_assert_int_eq(parse_http_message(req1, sizeof(req1), &conn.request_info),
	                 sizeof(req1) - 1);

	ctx.config[ENABLE_KEEP_ALIVE] = no;
	ck_assert_int_eq(should_keep_alive(&conn), 0);

	ctx.config[ENABLE_KEEP_ALIVE] = yes;
	ck_assert_int_eq(should_keep_alive(&conn), 1);

	conn.must_close = 1;
	ck_assert_int_eq(should_keep_alive(&conn), 0);

	conn.must_close = 0;
	parse_http_message(req2, sizeof(req2), &conn.request_info);
	ck_assert_int_eq(should_keep_alive(&conn), 0);

	parse_http_message(req3, sizeof(req3), &conn.request_info);
	ck_assert_int_eq(should_keep_alive(&conn), 0);

	parse_http_message(req4, sizeof(req4), &conn.request_info);
	ck_assert_int_eq(should_keep_alive(&conn), 1);

	conn.status_code = 401;
	ck_assert_int_eq(should_keep_alive(&conn), 0);

	conn.status_code = 200;
	conn.must_close = 1;
	ck_assert_int_eq(should_keep_alive(&conn), 0);
}
Esempio n. 3
0
static void test_should_keep_alive(void) {
  struct mg_connection conn;
  struct mg_context ctx;
  char req1[] = "GET / HTTP/1.1\r\n\r\n";
  char req2[] = "GET / HTTP/1.0\r\n\r\n";
  char req3[] = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n";
  char req4[] = "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n";

  memset(&conn, 0, sizeof(conn));
  conn.ctx = &ctx;
  ASSERT(parse_http_message(req1, sizeof(req1), &conn.request_info) ==
         sizeof(req1) - 1);

  ctx.config[ENABLE_KEEP_ALIVE] = "no";
  ASSERT(should_keep_alive(&conn) == 0);

  ctx.config[ENABLE_KEEP_ALIVE] = "yes";
  ASSERT(should_keep_alive(&conn) == 1);

  conn.must_close = 1;
  ASSERT(should_keep_alive(&conn) == 0);

  conn.must_close = 0;
  parse_http_message(req2, sizeof(req2), &conn.request_info);
  ASSERT(should_keep_alive(&conn) == 0);

  parse_http_message(req3, sizeof(req3), &conn.request_info);
  ASSERT(should_keep_alive(&conn) == 0);

  parse_http_message(req4, sizeof(req4), &conn.request_info);
  ASSERT(should_keep_alive(&conn) == 1);

  conn.status_code = 401;
  ASSERT(should_keep_alive(&conn) == 0);

  conn.status_code = 200;
  conn.must_close = 1;
  ASSERT(should_keep_alive(&conn) == 0);
}
Esempio n. 4
0
bool wsgi_call_application(Request* request)
{
  StartResponse* start_response=PyObject_NEW(StartResponse, &StartResponse_Type);//构造了一个自定义的对象
  PyObject* request_headers;
  PyObject* retval;
  PyObject* first_chunk;
  PyObject* buf;
  Py_ssize_t length;
  //printf("***********************in wsgi_call_application***********\n");
  start_response->request = request;


  /* From now on, `headers` stores the _response_ headers
   * (passed by the WSGI app) rather than the _request_ headers */
  request_headers = request->headers;	// 请求头headers转储
  request->headers = NULL;

  /* application(environ, start_response) call */
  retval = PyObject_CallFunctionObjArgs(	// 构造一个包装了wsgi_app可执行方法  请求头 客户端响应对象
    wsgi_app,
    request_headers,
    start_response,
    NULL /* sentinel */
  );

  Py_DECREF(request_headers);
  Py_DECREF(start_response);

  if(retval == NULL)
    return false;
   //printf("***********************go retval***********\n");
  /* The following code is somewhat magic, so worth an explanation.
   *
   * If the application we called was a generator, we have to call .next() on
   * it before we do anything else because that may execute code that
   * invokes `start_response` (which might not have been invoked yet).
   * Think of the following scenario:
   *
   *   def app(environ, start_response):
   *     start_response('200 Ok', ...)
   *     yield 'Hello World'
   *
   * That would make `app` return an iterator (more precisely, a generator).
   * Unfortunately, `start_response` wouldn't be called until the first item
   * of that iterator is requested; `start_response` however has to be called
   * _before_ the wsgi body is sent, because it passes the HTTP headers.
   *
   * If the application returned a list this would not be required of course,
   * but special-handling is painful - especially in C - so here's one generic
   * way to solve the problem:
   *
   * Look into the returned iterator in any case. This allows us to do other
   * optimizations, for example if the returned value is a list with exactly
   * one string in it, we can pick the string and throw away the list so bjoern
   * does not have to come back again and look into the iterator a second time.
   */
  

  if(PyList_Check(retval) && PyList_GET_SIZE(retval) == 1 &&
     PyString_Check(PyList_GET_ITEM(retval, 0)))
  {
    /* Optimize the most common case, a single string in a list: */
    PyObject* tmp = PyList_GET_ITEM(retval, 0);
	//printf("------------wsgi 返回迭代对象\n");
    Py_INCREF(tmp);
    Py_DECREF(retval);
    retval = tmp;
    //goto string; /* eeevil */
    if(PyString_GET_SIZE(retval)) {
      first_chunk = retval;
    } else {
      Py_DECREF(retval);
      first_chunk = NULL;
    }
  } else if(PyString_Check(retval)) {
	  //printf("------------wsgi 返回字符对象\n");
    /* According to PEP 333 strings should be handled like any other iterable,
     * i.e. sending the response item for item. "item for item" means
     * "char for char" if you have a string. -- I'm not that stupid. */
    //string:
    if(PyString_GET_SIZE(retval)) {
      first_chunk = retval;
    } else {
      Py_DECREF(retval);
      first_chunk = NULL;
    }
  } else if(FileWrapper_CheckExact(retval)) {
	//printf("------------wsgi 返回文件对象\n");
    request->state.use_sendfile = true;
    request->iterable = ((FileWrapper*)retval)->file;
    Py_INCREF(request->iterable);
    Py_DECREF(retval);
    request->iterator = NULL;
    first_chunk = NULL;
  } else {
	//printf("------------wsgi 返回其他普通对象\n");
    /* Generic iterable (list of length != 1, generator, ...) */
    request->iterable = retval;
    request->iterator = PyObject_GetIter(retval);
    if(request->iterator == NULL)
      return false;
    first_chunk = wsgi_iterable_get_next_chunk(request);
    if(first_chunk == NULL && PyErr_Occurred())
      return false;
  }

  if(request->headers == NULL) {
    /* It is important that this check comes *after* the call to
     * wsgi_iterable_get_next_chunk(), because in case the WSGI application
     * was an iterator, there's no chance start_response could be called
     * before. See above if you don't understand what I say. */
    PyErr_SetString(
      PyExc_RuntimeError,
      "wsgi application returned before start_response was called"
    );
    Py_DECREF(first_chunk);
    return false;
  }

  if(should_keep_alive(request)) {
    request->state.chunked_response = request->state.response_length_unknown;
    request->state.keep_alive = true;
  } else {
    request->state.keep_alive = false;
  }

  /* Get the headers and concatenate the first body chunk.
   * In the first place this makes the code more simple because afterwards
   * we can throw away the first chunk PyObject; but it also is an optimization:
   * At least for small responses, the complete response could be sent with
   * one send() call (in server.c:ev_io_on_write) which is a (tiny) performance
   * booster because less kernel calls means less kernel call overhead. */
  buf = PyString_FromStringAndSize(NULL, 1024);
  length = wsgi_getheaders(request, buf);
  if(length == 0) {
    Py_DECREF(first_chunk);
    Py_DECREF(buf);
    return false;
  }

  if(first_chunk == NULL) {
    _PyString_Resize(&buf, length);
    goto out;
  }

  if(request->state.chunked_response) {
    PyObject* new_chunk = wrap_http_chunk_cruft_around(first_chunk);
    Py_DECREF(first_chunk);
    assert(PyString_GET_SIZE(new_chunk) >= PyString_GET_SIZE(first_chunk) + 5);
    first_chunk = new_chunk;
  }

  assert(buf);
  _PyString_Resize(&buf, length + PyString_GET_SIZE(first_chunk));
  memcpy(PyString_AS_STRING(buf)+length, PyString_AS_STRING(first_chunk),
         PyString_GET_SIZE(first_chunk));

  Py_DECREF(first_chunk);
  //printf("&&&&&&&&&&&&&&&&&&& wsgi 结果字符:\n%s\n",buf);

out:
  request->state.wsgi_call_done = true;
  request->current_chunk = buf;
  request->current_chunk_p = 0;
  return true;
}