Civetweb 连接数据读取

本文详细介绍了Civetweb中用于处理HTTP请求的数据读取方法。包括如何从连接中读取并缓存数据,以及如何针对分块传输编码进行特殊处理。通过对核心函数mg_read及其内部实现mg_read_inner的深入剖析,帮助读者理解其工作原理。
摘要由CSDN通过智能技术生成

Civetweb 连接数据读取

  • int mg_read(struct mg_connection *conn, void *buf, size_t len)
    从conn中读取若干字节到buf指定的地址空间中,返回值是真正读取的字节数。
    该函数会把已经读到mg_connection.buf中的被缓存的数据拷贝到buf中,然后在继续从connection对应的socket中读取数据,放入到buf中。
int mg_read(struct mg_connection *conn, void *buf, size_t len) {
    switch ( conn->is_chunked ) {
    case 2:
    ¦   return -1;
    case 1:
    ¦   if (conn->content_len <= 0 ) conn->content_len = 0;
    ¦   if (conn->consumed_content < conn->content_len) return mg_read_inner(conn,buf,len);
    ¦   int i = 0;
    ¦   char str[64];
    ¦   while (1) {
    ¦   ¦   int c = mg_getc(conn);
       ¦if (c == EOF) return 0;
    ¦   ¦   if ( ! ( c == '\n' || c == '\r' ) ) {
    ¦   ¦   ¦   str[i++] = c;
    ¦   ¦   ¦   break;
    ¦   ¦   }
    ¦   }
    ¦   for (; i < (int)sizeof(str); i++) {
    ¦   ¦   int c = mg_getc(conn);                                                                                                                                                                                  
    ¦   ¦   if ( c == EOF ) return -1;
    ¦   ¦   str[i] = (char) c;
    ¦   ¦   if ( i > 0 && str[i] == '\n' && str[i-1] == '\r' ) break;
    ¦   }
    ¦   char *end = 0;
    ¦   long chunkSize = strtol(str,&end,16);
    ¦   if ( end != str+(i-1) ) return -1;
    ¦   if ( chunkSize == 0 ) {
       ¦conn->is_chunked = 2;
       ¦return 0;
    }
    ¦   conn->content_len += chunkSize;
    }
    return mg_read_inner(conn,buf,len);
}
  • int mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
    从conn中读取数据到buf指向的地址空间中,最多读取len个字节,最少读取该连接中剩余的content大小的字节数。
int mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
{                                                                                                                                                                                                                   
    int64_t n, buffered_len, nread;
    const char *body;

    /* If Content-Length is not set for a PUT or POST request, read until socket is closed */
    if (conn->consumed_content == 0 && conn->content_len == -1) {
    ¦   conn->content_len = INT64_MAX;
    ¦   conn->must_close = 1;
    }

    nread = 0;
    if (conn->consumed_content < conn->content_len) {
    ¦   /* Adjust number of bytes to read. */
    ¦   int64_t to_read = conn->content_len - conn->consumed_content;
    ¦   if (to_read < (int64_t) len) {
    ¦   ¦   len = (size_t) to_read;
    ¦   }

    ¦   /* Return buffered data */
    ¦   body = conn->buf + conn->request_len + conn->consumed_content;
    ¦   buffered_len = (int64_t)(&conn->buf[conn->data_len] - body);
    ¦   if (buffered_len > 0) {
    ¦   ¦   if (len < (size_t) buffered_len) {
    ¦   ¦   ¦   buffered_len = (int64_t) len;
    ¦   ¦   }
    ¦   ¦   memcpy(buf, body, (size_t) buffered_len);
    ¦   ¦   len -= buffered_len;
    ¦   ¦   conn->consumed_content += buffered_len;
    ¦   ¦   nread += buffered_len;
    ¦   ¦   buf = (char *) buf + buffered_len;
    ¦   }

    ¦   /* We have returned all buffered data. Read new data from the remote
    ¦   ¦  socket. */
    ¦   n = pull_all(NULL, conn, (char *) buf, (int64_t) len);
    ¦   nread = n >= 0 ? nread + n : n;
    }
    return nread;
}
  • static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
    从文件描述符或者conn中读取数据到buf指向的地址空间中,直到对端没有数据,
    或者对端已经关闭,抑或读取len个字节,才返回,调用成功返回读取的字节数
    失败返回-1.
static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
{
    int n, nread = 0;

    while (len > 0 && conn->ctx->stop_flag == 0) {
    ¦   n = pull(fp, conn, buf + nread, len);
    ¦   if (n < 0) {
    ¦   ¦   nread = n;  /* Propagate the error */                                                                                                                                                                   
    ¦   ¦   break;
    ¦   } else if (n == 0) {
    ¦   ¦   break;  /* No more data to read */
    ¦   } else {
    ¦   ¦   conn->consumed_content += n;
    ¦   ¦   nread += n;
    ¦   ¦   len -= n;
    ¦   }
    }

    return nread;
}
  • static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len)
    Read from IO channel - opened file descriptor, socket, or SSL descriptor. Return negative value on error, or number of bytes read on success.
  • 从打开的文件描述符中、ssl socket或者socket中读取数据,放到buf指向的空间中,最大读取的字节数为len调用成功返回实际读取到的字节数,失败则返回-1.
static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len)                                                                                                                                           
{
    int nread;

    if (fp != NULL) {
    ¦   /* Use read() instead of fread(), because if we're reading from the
    ¦   ¦  CGI pipe, fread() may block until IO buffer is filled up. We cannot
    ¦   ¦  afford to block and must pass all read bytes immediately to the
    ¦   ¦  client. */
    ¦   nread = read(fileno(fp), buf, (size_t) len);
#ifndef NO_SSL
    } else if (conn->ssl != NULL) {
    ¦   nread = SSL_read(conn->ssl, buf, len);
#endif
    } else {
    ¦   nread = recv(conn->client.sock, buf, (size_t) len, 0);
    }

    return conn->ctx->stop_flag ? -1 : nread;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值