Exemple #1
0
static void
ev_io_on_read(struct ev_loop* mainloop, ev_io* watcher, const int events)
{
  static char read_buf[READ_BUFFER_SIZE];

  Request* request = REQUEST_FROM_WATCHER(watcher);

  ssize_t read_bytes = read(
    request->client_fd,
    read_buf,
    READ_BUFFER_SIZE
  );

  GIL_LOCK(0);

  if(read_bytes <= 0) {
    if(errno != EAGAIN && errno != EWOULDBLOCK) {
      if(read_bytes == 0)
        DBG_REQ(request, "Client disconnected");
      else
        DBG_REQ(request, "Hit errno %d while read()ing", errno);
      close(request->client_fd);
      Request_free(request);
      ev_io_stop(mainloop, &request->ev_watcher);
    }
    goto out;
  }

  Request_parse(request, read_buf, (size_t)read_bytes);

  if(request->state.error_code) {
    DBG_REQ(request, "Parse error");
    request->current_chunk = PyString_FromString(
      http_error_messages[request->state.error_code]);
    assert(request->iterator == NULL);
  }
  else if(request->state.parse_finished) {
    if(!wsgi_call_application(request)) {
      assert(PyErr_Occurred());
      PyErr_Print();
      assert(!request->state.chunked_response);
      Py_XCLEAR(request->iterator);
      request->current_chunk = PyString_FromString(
        http_error_messages[HTTP_SERVER_ERROR]);
    }
  } else {
    /* Wait for more data */
    goto out;
  }

  ev_io_stop(mainloop, &request->ev_watcher);
  ev_io_init(&request->ev_watcher, &ev_io_on_write,
             request->client_fd, EV_WRITE);
  ev_io_start(mainloop, &request->ev_watcher);

out:
  GIL_UNLOCK(0);
  return;
}
Exemple #2
0
static void
ev_io_on_write(struct ev_loop* mainloop, ev_io* watcher, const int events)
{
  /* Since the response writing code is fairly complex, I'll try to give a short
   * overview of the different control flow paths etc.:
   *
   * On the very top level, there are two types of responses to distinguish:
   * A) sendfile responses
   * B) iterator/other responses
   *
   * These cases are handled by the 'on_write_sendfile' and 'on_write_chunk'
   * routines, respectively.  They use the 'do_sendfile' and 'do_send_chunk'
   * routines to do the actual write()-ing. The 'do_*' routines return true if
   * there's some data left to send in the current chunk (or, in the case of
   * sendfile, the end of the file has not been reached yet).
   *
   * When the 'do_*' routines return false, the 'on_write_*' routines have to
   * figure out if there's a next chunk to send (e.g. in the case of a response iterator).
   */
  Request* request = REQUEST_FROM_WATCHER(watcher);

  GIL_LOCK(0);

  write_state write_state;
  if(request->state.use_sendfile) {
    write_state = on_write_sendfile(mainloop, request);
  } else {
    write_state = on_write_chunk(mainloop, request);
  }

  switch(write_state) {
  case not_yet_done:
    break;
  case done:
    if(request->state.keep_alive) {
      DBG_REQ(request, "done, keep-alive");
      ev_io_stop(mainloop, &request->ev_watcher);
      Request_clean(request);
      Request_reset(request);
      ev_io_init(&request->ev_watcher, &ev_io_on_read,
                 request->client_fd, EV_READ);
      ev_io_start(mainloop, &request->ev_watcher);
    } else {
      DBG_REQ(request, "done, close");
      close_connection(mainloop, request);
    }
    break;
  case aborted:
    /* Response was aborted due to an error. We can't do anything graceful here
     * because at least one chunk is already sent... just close the connection. */
    close_connection(mainloop, request);
    break;
  }

  GIL_UNLOCK(0);
}
Exemple #3
0
static void
ev_io_on_request(struct ev_loop* mainloop, ev_io* watcher, const int events)
{
  int client_fd;
  struct sockaddr_in sockaddr;
  socklen_t addrlen;

  addrlen = sizeof(struct sockaddr_in);
  client_fd = accept(watcher->fd, (struct sockaddr*)&sockaddr, &addrlen);
  if(client_fd < 0) {
    DBG("Could not accept() client: errno %d", errno);
    return;
  }

  int flags = fcntl(client_fd, F_GETFL, 0);
  if(fcntl(client_fd, F_SETFL, (flags < 0 ? 0 : flags) | O_NONBLOCK) == -1) {
    DBG("Could not set_nonblocking() client %d: errno %d", client_fd, errno);
    return;
  }

  GIL_LOCK(0);
  Request* request = Request_new(client_fd, inet_ntoa(sockaddr.sin_addr));
  GIL_UNLOCK(0);

  DBG_REQ(request, "Accepted client %s:%d on fd %d",
          inet_ntoa(sockaddr.sin_addr), ntohs(sockaddr.sin_port), client_fd);

  ev_io_init(&request->ev_watcher, &ev_io_on_read,
             client_fd, EV_READ);
  ev_io_start(mainloop, &request->ev_watcher);
}
Exemple #4
0
static write_state
on_write_chunk(struct ev_loop* mainloop, Request* request)
{
  if (do_send_chunk(request))
    // data left to send in the current chunk
    return not_yet_done;

  if(request->iterator) {
    /* Reached the end of a chunk in the response iterator. Get next chunk. */
    PyObject* next_chunk = wsgi_iterable_get_next_chunk(request);
    if(next_chunk) {
      /* We found another chunk to send. */
      if(request->state.chunked_response) {
        request->current_chunk = wrap_http_chunk_cruft_around(next_chunk);
        Py_DECREF(next_chunk);
      } else {
        request->current_chunk = next_chunk;
      }
      assert(request->current_chunk_p == 0);
      return not_yet_done;

    } else {
      if(PyErr_Occurred()) {
        /* Trying to get the next chunk raised an exception. */
        PyErr_Print();
        DBG_REQ(request, "Exception in iterator, can not recover");
        return aborted;
      } else {
        /* This was the last chunk; cleanup. */
        Py_CLEAR(request->iterator);
        goto send_terminator_chunk;
      }
    }
  } else {
    /* We have no iterator to get more chunks from, so we're done.
     * Reasons we might end up in this place:
     * A) A parse or server error occurred
     * C) We just finished a chunked response with the call to 'do_send_chunk'
     *    above and now maybe have to send the terminating empty chunk.
     * B) We used chunked responses earlier in the response and
     *    are now sending the terminating empty chunk.
     */
    goto send_terminator_chunk;
  }

  assert(0); // unreachable

send_terminator_chunk:
  if(request->state.chunked_response) {
    /* We have to send a terminating empty chunk + \r\n */
    request->current_chunk = PyString_FromString("0\r\n\r\n");
    assert(request->current_chunk_p == 0);
    // Next time we get here, don't send the terminating empty chunk again.
    // XXX This is kind of a hack and should be refactored for easier understanding.
    request->state.chunked_response = false;
    return not_yet_done;
  } else {
    return done;
  }
}
Exemple #5
0
static void
ev_io_on_read(struct ev_loop* mainloop, ev_io* watcher, const int events)
{
    char read_buf[READ_BUFFER_SIZE];
    Request* request = ADDR_FROM_MEMBER(watcher, Request, ev_watcher);
    ssize_t read_bytes = read(request->client_fd, read_buf, READ_BUFFER_SIZE);

    DBG_REQ(request, "read %zd bytes", read_bytes);

    GIL_LOCK(0);

    if(read_bytes == -1) {
        if(errno != EAGAIN && errno != EWOULDBLOCK) {
            close(request->client_fd);
            Request_free(request);
            ev_io_stop(mainloop, &request->ev_watcher);
        }
        goto out;
    }

    Request_parse(request, read_buf, read_bytes);

    if(request->state.error) {
        DBG_REQ(request, "Parse error");
        set_error(request, request->state.error_code);
    }
    else if(request->state.parse_finished) {
        DBG_REQ(request, "Parse done");
        if(!wsgi_call_application(request)) {
            assert(PyErr_Occurred());
            PyErr_Print();
            set_error(request, HTTP_SERVER_ERROR);
        }
    } else {
        DBG_REQ(request, "Waiting for more data");
        goto out;
    }

    ev_io_stop(mainloop, &request->ev_watcher);
    ev_io_init(&request->ev_watcher, &ev_io_on_write,
               request->client_fd, EV_WRITE);
    ev_io_start(mainloop, &request->ev_watcher);

out:
    GIL_UNLOCK(0);
    return;
}
Exemple #6
0
static void
close_connection(struct ev_loop *mainloop, Request* request)
{
  DBG_REQ(request, "Closing socket");
  ev_io_stop(mainloop, &request->ev_watcher);
  close(request->client_fd);
  Request_free(request);
}
Exemple #7
0
static void
ev_io_on_write(struct ev_loop* mainloop, ev_io* watcher, const int events)
{
    GIL_LOCK(0);

    Request* request = ADDR_FROM_MEMBER(watcher, Request, ev_watcher);
    assert(request->current_chunk);

    if(send_chunk(request))
        goto notfinished;

    if(request->iterable) {
        PyObject* next_chunk;
        DBG_REQ(request, "Getting next iterable chunk.");
        next_chunk = wsgi_iterable_get_next_chunk(request);
        if(next_chunk == NULL) {
            if(PyErr_Occurred()) {
                /* Internal server error. */
                PyErr_Print();
                set_error(request, HTTP_SERVER_ERROR);
                goto notfinished;
            }
            DBG_REQ(request, "Iterable exhausted");
            goto bye;
        }
        request->current_chunk = next_chunk;
        assert(request->current_chunk_p == 0);
        goto notfinished;
    }

bye:
    DBG_REQ(request, "Done");

    /* Everything done, bye client! */
    ev_io_stop(mainloop, &request->ev_watcher);
    close(request->client_fd);
    Request_free(request);

notfinished:
    GIL_UNLOCK(0);
}
Exemple #8
0
static bool
send_chunk(Request* request)
{
    ssize_t sent_bytes;

    assert(request->current_chunk != NULL);
    assert(request->current_chunk_p != PyString_GET_SIZE(request->current_chunk));

    DBG_REQ(request, "Sending next chunk");
    sent_bytes = write(
        request->client_fd,
        PyString_AS_STRING(request->current_chunk) + request->current_chunk_p,
        PyString_GET_SIZE(request->current_chunk) - request->current_chunk_p
    );

    if(sent_bytes == -1) {
        if(errno == EAGAIN || errno == EWOULDBLOCK) {
            /* Try again later */
            return 1;
        } else {
            /* Serious transmission failure. Hang up. */
            fprintf(stderr, "Client %d hit errno %d\n", request->client_fd, errno);
            Py_DECREF(request->current_chunk);
            Py_XDECREF(request->iterable);
            request->iterable = NULL; /* to make ev_io_on_write jump right into 'bye' */
            return 0;
        }
    }

    DBG_REQ(request, "Sent %zd bytes from %p", sent_bytes, request->current_chunk);
    request->current_chunk_p += sent_bytes;
    if(request->current_chunk_p == PyString_GET_SIZE(request->current_chunk)) {
        DBG_REQ(request, "Done with string %p", request->current_chunk);
        Py_DECREF(request->current_chunk);
        request->current_chunk = NULL;
        request->current_chunk_p = 0;
        return 0;
    }
    return 1;
}
Exemple #9
0
static void on_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
	Request* request;
	dprint("go on_read");
	request =(Request*)handle->data;
	GIL_LOCK(0);
	if (nread <= 0) {
		//@@@@@@@@@@@@@@@uv_err_t err = uv_last_error(loop);
		//@@@@@@@@@@@@@@@UVERR(err, "uv read error");
		if(nread == 0)
		        dprint("Client disconnected");
		uv_close((uv_handle_t*)handle, on_close);
		Request_free(request);
		if (buf.base) {
		  free(buf.base);
		}
		goto out;
	}
    Request_parse(request, buf.base, nread);	//处理Request解析
	free(buf.base);
    if(request->state.error_code) {
      DBG_REQ(request, "Parse error");
      request->current_chunk = PyString_FromString(http_error_messages[request->state.error_code]);//处理有错误的信息返回
	  assert(request->iterator == NULL);
	  //@@@@@@@@@ uv_close((uv_handle_t*) &request->ev_watcher, on_close);//解析有错误的请求直接关闭客户端连接
	  //@@@@@@@@@@ Request_free(request);
	  //@@@@@@@@@ goto out;
    }
    else if(request->state.parse_finished) {	// 解析好后
	  dprint("执行wsgi程序 >>>");
      if(!wsgi_call_application(request)) {	// 执行wsgi
	    dprint("wsgi执行包含错误");
        assert(PyErr_Occurred());
        PyErr_Print();	//打印python错误的跟踪堆栈信息
        assert(!request->state.chunked_response);
        Py_XCLEAR(request->iterator);
        request->current_chunk = PyString_FromString(	//返回错误信息给客户端
          http_error_messages[HTTP_SERVER_ERROR]);
      }
    } else {
      /* Wait for more data */
      goto out;
    }
    dprint("开始客户端数据返回 >>>");
    while(request->current_chunk){	//客户端返回循环
	  io_write(request);
    }

	out:
	  GIL_UNLOCK(0);
	  return;
}
Exemple #10
0
static void on_connection(uv_stream_t* server, int status) {	//当有客户端连接时触发
	int r;
	Request* request;
	struct sockaddr_in sockaddr;	//定义套接字地址
	socklen_t addrlen;
	uv_stream_t* handle;
	dprint("on connection.");
	if (status != 0) {				//状态判断, 状态必须为0
	fprintf(stderr, "Connect error %d\n",
		uv_last_error(loop).code);
	}
	ASSERT(status == 0);

	handle = malloc(sizeof(uv_tcp_t));
	GIL_LOCK(0);
	request = Request_init();
	GIL_UNLOCK(0);

	r = uv_tcp_init(loop, (uv_tcp_t*)handle);//初始化连接流结构体
	ASSERT(r == 0);

	r = uv_accept(server, handle);
	ASSERT(r == 0);

	//-----------------得到客户端信息
	addrlen = sizeof(struct sockaddr_in);
	r = uv_tcp_getpeername((uv_tcp_t *)handle, (struct sockaddr *)&sockaddr, &addrlen);
	ASSERT(r == 0);
	
	request->client_addr = PyString_FromString(inet_ntoa(sockaddr.sin_addr));
	request->client_fd = 1;//request->ev_watcher.socket;
	request->ev_watcher = handle;
	handle->data = request;
	DBG_REQ(request, "Accepted client %s:%d on fd %d",
		  inet_ntoa(sockaddr.sin_addr), ntohs(sockaddr.sin_port), (int)(GET_HANDLE_FD(handle)));
	//@@@@@@@@@@@@@@@@@free(&sockaddr);
	//-----------------读事件循环
	r = uv_read_start(handle, on_alloc, on_read);
	ASSERT(r == 0);
}
Exemple #11
0
/* XXX too many gotos */
static void
ev_io_on_write(struct ev_loop* mainloop, ev_io* watcher, const int events)
{
  Request* request = REQUEST_FROM_WATCHER(watcher);

  GIL_LOCK(0);

  if(request->state.use_sendfile) {
    /* sendfile */
    if(request->current_chunk) {
      /* current_chunk contains the HTTP headers */
      if(send_chunk(request))
        goto out;
      assert(!request->current_chunk_p);
      /* abuse current_chunk_p to store the file fd */
      request->current_chunk_p = PyObject_AsFileDescriptor(request->iterable);
      goto out;
    }
    if(do_sendfile(request))
      goto out;
  } else {
    /* iterable */
    if(send_chunk(request))
      goto out;

    if(request->iterator) {
      PyObject* next_chunk;
      next_chunk = wsgi_iterable_get_next_chunk(request);
      if(next_chunk) {
        if(request->state.chunked_response) {
          request->current_chunk = wrap_http_chunk_cruft_around(next_chunk);
          Py_DECREF(next_chunk);
        } else {
          request->current_chunk = next_chunk;
        }
        assert(request->current_chunk_p == 0);
        goto out;
      } else {
        if(PyErr_Occurred()) {
          PyErr_Print();
          /* We can't do anything graceful here because at least one
           * chunk is already sent... just close the connection */
          DBG_REQ(request, "Exception in iterator, can not recover");
          ev_io_stop(mainloop, &request->ev_watcher);
          close(request->client_fd);
          Request_free(request);
          goto out;
        }
        Py_CLEAR(request->iterator);
      }
    }

    if(request->state.chunked_response) {
      /* We have to send a terminating empty chunk + \r\n */
      request->current_chunk = PyString_FromString("0\r\n\r\n");
      assert(request->current_chunk_p == 0);
      request->state.chunked_response = false;
      goto out;
    }
  }

  ev_io_stop(mainloop, &request->ev_watcher);
  if(request->state.keep_alive) {
    DBG_REQ(request, "done, keep-alive");
    Request_clean(request);
    Request_reset(request);
    ev_io_init(&request->ev_watcher, &ev_io_on_read,
               request->client_fd, EV_READ);
    ev_io_start(mainloop, &request->ev_watcher);
  } else {
    DBG_REQ(request, "done, close");
    close(request->client_fd);
    Request_free(request);
  }

out:
  GIL_UNLOCK(0);
}
Exemple #12
0
static void io_write(Request* request)
{
  //GIL_LOCK(0);

  if(request->state.use_sendfile) {
	dprint("发送文件给客户端");
    /* sendfile */
    if(request->current_chunk && send_chunk(request))
      goto out;
    /* abuse current_chunk_p to store the file fd */
    request->current_chunk_p = PyObject_AsFileDescriptor(request->iterable);
    if(do_sendfile(request))
      goto out;
  } else {
    dprint("发送字符");
    /* iterable */
	if(send_chunk(request)){
	  dprint("一次发送即完成");
	  //uv_close((uv_handle_t*) &request->ev_watcher, _http_uv__on_close__cb);
      goto out;
	}

    if(request->iterator) {
      PyObject* next_chunk;
	  dprint("request迭代");
      next_chunk = wsgi_iterable_get_next_chunk(request);
      if(next_chunk) {
		dprint("下一块chunk发送");
        if(request->state.chunked_response) {
          request->current_chunk = wrap_http_chunk_cruft_around(next_chunk);
          Py_DECREF(next_chunk);
        } else {
          request->current_chunk = next_chunk;
        }
        assert(request->current_chunk_p == 0);
		//io_write(request);
        goto out;
      } else {
        if(PyErr_Occurred()) {
		  uv_err_t err;
		  dprint("迭代出错");
          PyErr_Print();
          DBG_REQ(request, "Exception in iterator, can not recover");
		  uv_close((uv_handle_t*) request->ev_watcher, on_close);
		  Request_free(request);
		  err = uv_last_error(loop);
		  UVERR(err, "uv_write error on next chunk");
		  ASSERT(0);
          goto out;
        }
		dprint("没有下一块chunk");
        Py_CLEAR(request->iterator);
      }
    }

    if(request->state.chunked_response) {
      dprint("如果是chunked_response 发送收尾数据,并置空chunked_response");
      /* We have to send a terminating empty chunk + \r\n */
      request->current_chunk = PyString_FromString("0\r\n\r\n");
      assert(request->current_chunk_p == 0);
	  //io_write(request);
      request->state.chunked_response = false;
      goto out;
    }
  }
  dprint("响应完成");
  if(request->state.keep_alive) {
    DBG_REQ(request, "done, keep-alive");
    Request_clean(request);
    Request_reset(request);
  } else {
	dprint("done not keep alive");
	uv_close((uv_handle_t*) request->ev_watcher, on_close);
	Request_free(request);
  }

out:
  dprint("本次字符发送结束");
  //GIL_UNLOCK(0);
  return;
}
Exemple #13
0
static void
ev_io_on_read(struct ev_loop* mainloop, ev_io* watcher, const int events)
{
  static char read_buf[READ_BUFFER_SIZE];

  Request* request = REQUEST_FROM_WATCHER(watcher);
  read_state read_state;

  ssize_t read_bytes = read(
    request->client_fd,
    read_buf,
    READ_BUFFER_SIZE
  );

  GIL_LOCK(0);

  if (read_bytes == 0) {
    /* Client disconnected */
    read_state = aborted;
    DBG_REQ(request, "Client disconnected");
  } else if (read_bytes < 0) {
    /* Would block or error */
    if(errno == EAGAIN || errno == EWOULDBLOCK) {
      read_state = not_yet_done;
    } else {
      read_state = aborted;
      DBG_REQ(request, "Hit errno %d while read()ing", errno);
    }
  } else {
    /* OK, either expect more data or done reading */
    Request_parse(request, read_buf, (size_t)read_bytes);
    if(request->state.error_code) {
      /* HTTP parse error */
      read_state = done;
      DBG_REQ(request, "Parse error");
      request->current_chunk = PyString_FromString(
        http_error_messages[request->state.error_code]);
      assert(request->iterator == NULL);
    } else if(request->state.parse_finished) {
      /* HTTP parse successful */
      read_state = done;
      bool wsgi_ok = wsgi_call_application(request);
      if (!wsgi_ok) {
        /* Response is "HTTP 500 Internal Server Error" */
        DBG_REQ(request, "WSGI app error");
        assert(PyErr_Occurred());
        PyErr_Print();
        assert(!request->state.chunked_response);
        Py_XCLEAR(request->iterator);
        request->current_chunk = PyString_FromString(
          http_error_messages[HTTP_SERVER_ERROR]);
      }
    } else {
      /* Wait for more data */
      read_state = not_yet_done;
    }
  }

  switch (read_state) {
  case not_yet_done:
    break;
  case done:
    DBG_REQ(request, "Stop read watcher, start write watcher");
    ev_io_stop(mainloop, &request->ev_watcher);
    ev_io_init(&request->ev_watcher, &ev_io_on_write,
               request->client_fd, EV_WRITE);
    ev_io_start(mainloop, &request->ev_watcher);
    break;
  case aborted:
    close_connection(mainloop, request);
    break;
  }

  GIL_UNLOCK(0);
}