Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
QWFLS
arduino-esp32
提交
ee88c42c
A
arduino-esp32
项目概览
QWFLS
/
arduino-esp32
与 Fork 源项目一致
从无法访问的项目Fork
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
A
arduino-esp32
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
ee88c42c
编写于
10月 01, 2020
作者:
C
Clickau
提交者:
GitHub
10月 01, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add support for following redirects in HTTPClient (#4240)
上级
837cc3d2
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
172 addition
and
17 deletion
+172
-17
libraries/HTTPClient/src/HTTPClient.cpp
libraries/HTTPClient/src/HTTPClient.cpp
+145
-17
libraries/HTTPClient/src/HTTPClient.h
libraries/HTTPClient/src/HTTPClient.h
+27
-0
未找到文件。
libraries/HTTPClient/src/HTTPClient.cpp
浏览文件 @
ee88c42c
...
...
@@ -548,29 +548,106 @@ int HTTPClient::sendRequest(const char * type, String payload)
*/
int
HTTPClient
::
sendRequest
(
const
char
*
type
,
uint8_t
*
payload
,
size_t
size
)
{
// connect to server
if
(
!
connect
())
{
return
returnError
(
HTTPC_ERROR_CONNECTION_REFUSED
);
}
int
code
;
bool
redirect
=
false
;
uint16_t
redirectCount
=
0
;
do
{
// wipe out any existing headers from previous request
for
(
size_t
i
=
0
;
i
<
_headerKeysCount
;
i
++
)
{
if
(
_currentHeaders
[
i
].
value
.
length
()
>
0
)
{
_currentHeaders
[
i
].
value
.
clear
();
}
}
if
(
payload
&&
size
>
0
)
{
addHeader
(
F
(
"Content-Length"
),
String
(
size
));
}
log_d
(
"request type: '%s' redirCount: %d
\n
"
,
type
,
redirectCount
);
// connect to server
if
(
!
connect
())
{
return
returnError
(
HTTPC_ERROR_CONNECTION_REFUSED
);
}
// send Header
if
(
!
sendHeader
(
type
))
{
return
returnError
(
HTTPC_ERROR_SEND_HEADER_FAILED
);
}
if
(
payload
&&
size
>
0
)
{
addHeader
(
F
(
"Content-Length"
),
String
(
size
));
}
// send Payload if needed
if
(
payload
&&
size
>
0
)
{
if
(
_client
->
write
(
&
payload
[
0
],
size
)
!=
size
)
{
return
returnError
(
HTTPC_ERROR_SEND_PAYLOAD_FAILED
);
// send Header
if
(
!
sendHeader
(
type
))
{
return
returnError
(
HTTPC_ERROR_SEND_HEADER_FAILED
);
}
// send Payload if needed
if
(
payload
&&
size
>
0
)
{
if
(
_client
->
write
(
&
payload
[
0
],
size
)
!=
size
)
{
return
returnError
(
HTTPC_ERROR_SEND_PAYLOAD_FAILED
);
}
}
code
=
handleHeaderResponse
();
Serial
.
printf
(
"sendRequest code=%d
\n
"
,
code
);
// Handle redirections as stated in RFC document:
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
//
// Implementing HTTP_CODE_FOUND as redirection with GET method,
// to follow most of existing user agent implementations.
//
redirect
=
false
;
if
(
_followRedirects
!=
HTTPC_DISABLE_FOLLOW_REDIRECTS
&&
redirectCount
<
_redirectLimit
&&
_location
.
length
()
>
0
)
{
switch
(
code
)
{
// redirecting using the same method
case
HTTP_CODE_MOVED_PERMANENTLY
:
case
HTTP_CODE_TEMPORARY_REDIRECT
:
{
if
(
// allow to force redirections on other methods
// (the RFC require user to accept the redirection)
_followRedirects
==
HTTPC_FORCE_FOLLOW_REDIRECTS
||
// allow GET and HEAD methods without force
!
strcmp
(
type
,
"GET"
)
||
!
strcmp
(
type
,
"HEAD"
)
)
{
redirectCount
+=
1
;
log_d
(
"following redirect (the same method): '%s' redirCount: %d
\n
"
,
_location
.
c_str
(),
redirectCount
);
if
(
!
setURL
(
_location
))
{
log_d
(
"failed setting URL for redirection
\n
"
);
// no redirection
break
;
}
// redirect using the same request method and payload, diffrent URL
redirect
=
true
;
}
break
;
}
// redirecting with method dropped to GET or HEAD
// note: it does not need `HTTPC_FORCE_FOLLOW_REDIRECTS` for any method
case
HTTP_CODE_FOUND
:
case
HTTP_CODE_SEE_OTHER
:
{
redirectCount
+=
1
;
log_d
(
"following redirect (dropped to GET/HEAD): '%s' redirCount: %d
\n
"
,
_location
.
c_str
(),
redirectCount
);
if
(
!
setURL
(
_location
))
{
log_d
(
"failed setting URL for redirection
\n
"
);
// no redirection
break
;
}
// redirect after changing method to GET/HEAD and dropping payload
type
=
"GET"
;
payload
=
nullptr
;
size
=
0
;
redirect
=
true
;
break
;
}
default:
break
;
}
}
}
}
while
(
redirect
);
// handle Server Response (Header)
return
returnError
(
handleHeaderResponse
()
);
return
returnError
(
code
);
}
/**
...
...
@@ -1143,6 +1220,10 @@ int HTTPClient::handleHeaderResponse()
transferEncoding
=
headerValue
;
}
if
(
headerName
.
equalsIgnoreCase
(
"Location"
))
{
_location
=
headerValue
;
}
for
(
size_t
i
=
0
;
i
<
_headerKeysCount
;
i
++
)
{
if
(
_currentHeaders
[
i
].
key
.
equalsIgnoreCase
(
headerName
))
{
_currentHeaders
[
i
].
value
=
headerValue
;
...
...
@@ -1320,3 +1401,50 @@ int HTTPClient::returnError(int error)
}
return
error
;
}
void
HTTPClient
::
setFollowRedirects
(
followRedirects_t
follow
)
{
_followRedirects
=
follow
;
}
void
HTTPClient
::
setRedirectLimit
(
uint16_t
limit
)
{
_redirectLimit
=
limit
;
}
/**
* set the URL to a new value. Handy for following redirects.
* @param url
*/
bool
HTTPClient
::
setURL
(
const
String
&
url
)
{
// if the new location is only a path then only update the URI
if
(
url
&&
url
[
0
]
==
'/'
)
{
_uri
=
url
;
clear
();
return
true
;
}
if
(
!
url
.
startsWith
(
_protocol
+
':'
))
{
log_d
(
"new URL not the same protocol, expected '%s', URL: '%s'
\n
"
,
_protocol
.
c_str
(),
url
.
c_str
());
return
false
;
}
// check if the port is specified
int
indexPort
=
url
.
indexOf
(
':'
,
6
);
// find the first ':' excluding the one from the protocol
int
indexURI
=
url
.
indexOf
(
'/'
,
7
);
// find where the URI starts to make sure the ':' is not part of it
if
(
indexPort
==
-
1
||
indexPort
>
indexURI
)
{
// the port is not specified
_port
=
(
_protocol
==
"https"
?
443
:
80
);
}
// disconnect but preserve _client (clear _canReuse so disconnect will close the connection)
_canReuse
=
false
;
disconnect
(
true
);
return
beginInternal
(
url
,
_protocol
.
c_str
());
}
const
String
&
HTTPClient
::
getLocation
(
void
)
{
return
_location
;
}
\ No newline at end of file
libraries/HTTPClient/src/HTTPClient.h
浏览文件 @
ee88c42c
...
...
@@ -119,6 +119,24 @@ typedef enum {
HTTPC_TE_CHUNKED
}
transferEncoding_t
;
/**
* redirection follow mode.
* + `HTTPC_DISABLE_FOLLOW_REDIRECTS` - no redirection will be followed.
* + `HTTPC_STRICT_FOLLOW_REDIRECTS` - strict RFC2616, only requests using
* GET or HEAD methods will be redirected (using the same method),
* since the RFC requires end-user confirmation in other cases.
* + `HTTPC_FORCE_FOLLOW_REDIRECTS` - all redirections will be followed,
* regardless of a used method. New request will use the same method,
* and they will include the same body data and the same headers.
* In the sense of the RFC, it's just like every redirection is confirmed.
*/
typedef
enum
{
HTTPC_DISABLE_FOLLOW_REDIRECTS
,
HTTPC_STRICT_FOLLOW_REDIRECTS
,
HTTPC_FORCE_FOLLOW_REDIRECTS
}
followRedirects_t
;
#ifdef HTTPCLIENT_1_1_COMPATIBLE
class
TransportTraits
;
typedef
std
::
unique_ptr
<
TransportTraits
>
TransportTraitsPtr
;
...
...
@@ -156,6 +174,11 @@ public:
void
setConnectTimeout
(
int32_t
connectTimeout
);
void
setTimeout
(
uint16_t
timeout
);
// Redirections
void
setFollowRedirects
(
followRedirects_t
follow
);
void
setRedirectLimit
(
uint16_t
limit
);
// max redirects to follow for a single request
bool
setURL
(
const
String
&
url
);
void
useHTTP10
(
bool
usehttp10
=
true
);
/// request handling
...
...
@@ -182,6 +205,7 @@ public:
int
getSize
(
void
);
const
String
&
getLocation
(
void
);
WiFiClient
&
getStream
(
void
);
WiFiClient
*
getStreamPtr
(
void
);
...
...
@@ -235,6 +259,9 @@ protected:
int
_returnCode
=
0
;
int
_size
=
-
1
;
bool
_canReuse
=
false
;
followRedirects_t
_followRedirects
=
HTTPC_DISABLE_FOLLOW_REDIRECTS
;
uint16_t
_redirectLimit
=
10
;
String
_location
;
transferEncoding_t
_transferEncoding
=
HTTPC_TE_IDENTITY
;
};
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录