Lwip-2.1.3, Http client添加post方法

Lwip-2.1.3源码中提供了http client接口,但是默认只有GET方法,如何基于源码最小改动添加POST方法?
lwip/src/apps/http/http_client.c

GET 和 POST 报文区别这里不表。

1、http_client.c中GET的基础报文:

	/* GET request basic */
	#define HTTPC_REQ_11 "GET %s HTTP/1.1\r\n" /* URI */\
    "User-Agent: %s\r\n" /* User-Agent */ \
    "Accept: */*\r\n" \
    "Connection: Close\r\n" /* we don't support persistent connections, yet */ \
    "\r\n"
	#define HTTPC_REQ_11_FORMAT(uri) HTTPC_REQ_11, uri, HTTPC_CLIENT_AGENT

	/* GET request with host */
	#define HTTPC_REQ_11_HOST "GET %s HTTP/1.1\r\n" /* URI */\
    "User-Agent: %s\r\n" /* User-Agent */ \
    "Accept: */*\r\n" \
    "Host: %s\r\n" /* server name */ \
    "Connection: Close\r\n" /* we don't support persistent connections, yet */ \
    "\r\n"
	#define HTTPC_REQ_11_HOST_FORMAT(uri, srv_name) HTTPC_REQ_11_HOST, uri, HTTPC_CLIENT_AGENT, srv_name

	/* GET request with proxy */
	#define HTTPC_REQ_11_PROXY "GET http://%s%s HTTP/1.1\r\n" /* HOST, URI */\
    "User-Agent: %s\r\n" /* User-Agent */ \
    "Accept: */*\r\n" \
    "Host: %s\r\n" /* server name */ \
    "Connection: Close\r\n" /* we don't support persistent connections, yet */ \
    "\r\n"
	#define HTTPC_REQ_11_PROXY_FORMAT(host, uri, srv_name) HTTPC_REQ_11_PROXY, host, uri, HTTPC_CLIENT_AGENT, srv_name

	/* GET request with proxy (non-default server port) */
	#define HTTPC_REQ_11_PROXY_PORT "GET http://%s:%d%s HTTP/1.1\r\n" /* HOST, host-port, URI */\
    "User-Agent: %s\r\n" /* User-Agent */ \
    "Accept: */*\r\n" \
    "Host: %s\r\n" /* server name */ \
    "Connection: Close\r\n" /* we don't support persistent connections, yet */ \
    "\r\n"
	#define HTTPC_REQ_11_PROXY_PORT_FORMAT(host, host_port, uri, srv_name) HTTPC_REQ_11_PROXY_PORT, host, host_port, uri, HTTPC_CLIENT_AGENT, srv_name

类比写出 POST的基础报文格式(post标准报文格式自行查找资料):

/* POST request basic */  
#define HTTPC_REQ_11_POST "POST %s HTTP/1.1\r\n" /* URI */\
    "User-Agent: %s\r\n" /* User-Agent */ \
    "Accept: */*\r\n" \
    "Content-Type: application/x-www-form-urlencoded\r\n" \
    "Content-Length: %d\r\n" \
    "Connection: Close\r\n" /* we don't support persistent connections, yet */\
    "\r\n" \
    "%s"
      
#define HTTPC_REQ_11_FORMAT_POST(uri, arglen, args)  HTTPC_REQ_11_POST, uri, HTTPC_CLIENT_AGENT, arglen, args
      
/* POST request with host */
#define HTTPC_REQ_11_HOST_POST "POST %s HTTP/1.1\r\n" /* URI */\
    "User-Agent: %s\r\n" /* User-Agent */ \
    "Accept: */*\r\n" \
    "Host: %s\r\n" /* server name */ \
    "Content-Type: application/x-www-form-urlencoded\r\n" \
    "Content-Length: %d\r\n" \
    "Connection: Close\r\n" /* we don't support persistent connections, yet */ \
    "\r\n" \
    "%s"
      
#define HTTPC_REQ_11_HOST_FORMAT_POST(uri, srv_name, arglen, args) HTTPC_REQ_11_HOST, uri, HTTPC_CLIENT_AGENT, srv_name, arglen, args

Content-Type可以有多种,可以根据不同需求调整。
这里没有写出post使用代理的报文(因为没用到),需要的话可以参照GET的代理报文。
2、生成完整报文函数:
httpclient模块使用 httpc_create_request_string 函数生成 GET 报文,所以可以从这个函数着手。

static int
httpc_create_request_string(const httpc_connection_t *settings, const char* server_name, int server_port, const char* uri,
                            int use_host, char *buffer, size_t buffer_size)
{
  if (settings->use_proxy) {
    LWIP_ASSERT("server_name != NULL", server_name != NULL);
    if (server_port != HTTP_DEFAULT_PORT) {
      return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_PORT_FORMAT(server_name, server_port, uri, server_name));
    } else {
      return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_FORMAT(server_name, uri, server_name));
    }
  } else if (use_host) {
    LWIP_ASSERT("server_name != NULL", server_name != NULL);
    return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT(uri, server_name));
  } else {
    return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT(uri));
  }
}

这里先撇开代理不看,添加使用post的分支:

static int
httpc_create_request_string(const httpc_connection_t *settings, const char* server_name, int server_port, const char* uri,
                            int use_host, char *buffer, size_t buffer_size)
{
  if (settings->use_proxy) {
    LWIP_ASSERT("server_name != NULL", server_name != NULL);
    if (server_port != HTTP_DEFAULT_PORT) {
      return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_PORT_FORMAT(server_name, server_port, uri, server_name));
    } else {
      return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_FORMAT(server_name, uri, server_name));
    }
  } else if (use_host) {
    LWIP_ASSERT("server_name != NULL", server_name != NULL);
    if (USE_POST){
		return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT_POST(uri, server_name, ARGLENS, ARGS));
	}
    return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT(uri, server_name));
  } else {
  	if (USE_POST){
    	return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT_POST(uri, ARGLENS, ARGS));
    }
    return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT(uri));
  }
}

思考:

	USE_POST, ARGLENS, ARGS 如何来?

3、修改 httpc_connection_t
从函数中可以看出判断是否使用代理使用的是 settings->use_proxy 。
settings类型:

typedef struct _httpc_connection {
  ip_addr_t proxy_addr;
  u16_t proxy_port;
  u8_t use_proxy;
  /* @todo: add username:pass? */

#if LWIP_ALTCP
  altcp_allocator_t *altcp_allocator;
#endif

  /* this callback is called when the transfer is finished (or aborted) */
  httpc_result_fn result_fn;
  /* this callback is called after receiving the http headers
     It can abort the connection by returning != ERR_OK */
  httpc_headers_done_fn headers_done_fn;
} httpc_connection_t;

同样可以在该结构体中添加触发使用 post 的成员变量,类似如下:

typedef struct _httpc_connection {
  ip_addr_t proxy_addr;
  u16_t proxy_port;
  u8_t use_proxy;
  /* @todo: add username:pass? */

#if LWIP_ALTCP
  altcp_allocator_t *altcp_allocator;
#endif

  /* this callback is called when the transfer is finished (or aborted) */
  httpc_result_fn result_fn;
  /* this callback is called after receiving the http headers
     It can abort the connection by returning != ERR_OK */
  httpc_headers_done_fn headers_done_fn;
  
  u8_t  use_post;
  u8_t  arglen;
  u8_t* args;
} httpc_connection_t;
总结:

修改后的_httpc_connection 定义如下:

typedef struct _httpc_connection {
  ip_addr_t proxy_addr;
  u16_t proxy_port;
  u8_t use_proxy;
  /* @todo: add username:pass? */

#if LWIP_ALTCP
  altcp_allocator_t *altcp_allocator;
#endif

  /* this callback is called when the transfer is finished (or aborted) */
  httpc_result_fn result_fn;
  /* this callback is called after receiving the http headers
     It can abort the connection by returning != ERR_OK */
  httpc_headers_done_fn headers_done_fn;
  
  u8_t  use_post;
  u8_t  arglen;
  u8_t* args;
} httpc_connection_t;

修改后的httpc_create_request_string 函数如下:

static int
httpc_create_request_string(const httpc_connection_t *settings, const char* server_name, int server_port, const char* uri,
                            int use_host, char *buffer, size_t buffer_size)
{
  if (settings->use_proxy) {
    LWIP_ASSERT("server_name != NULL", server_name != NULL);
    if (server_port != HTTP_DEFAULT_PORT) {
      return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_PORT_FORMAT(server_name, server_port, uri, server_name));
    } else {
      return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_FORMAT(server_name, uri, server_name));
    }
  } else if (use_host) {
    LWIP_ASSERT("server_name != NULL", server_name != NULL);
    if (settings->use_post){
		return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT_POST(uri, server_name, settings->arglen, settings->args));
	}
    return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT(uri, server_name));
  } else {
  	if (settings->use_post){
    	return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT_POST(uri, settings->arglen, settings->args));
    }
    return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT(uri));
  }
}
使用:
static 
err_t http_rev_func(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
  LWIP_PLATFORM_DIAG(("this is  http_rev_func\r\n"));
  pbuf_free(p);
  return ERR_OK;
}
 
 httpc_connection_t setting = {    .use_proxy = 0,
                                   .result_fn = NULL,
                                   .headers_done_fn = NULL};
// 使用 GET 方法                                   
httpc_get_file(&ser_ipaddr, 8080,"/index.html", NULL, http_rev_func, NULL, NULL);

// 使用 POST 方法
setting.use_post = 1;
setting.arglen = 0;
setting.args = NULL;
httpc_get_file(&ser_ipaddr, 8080,"/index.html", &setting , http_rev_func, NULL, NULL);
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值