Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
dify
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tech
dify
Commits
2008986f
Unverified
Commit
2008986f
authored
Mar 11, 2024
by
Yeuoly
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat
parent
1a57951d
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
197 additions
and
20 deletions
+197
-20
ssrf_proxy.py
api/core/helper/ssrf_proxy.py
+0
-1
http_executor.py
api/core/workflow/nodes/http_request/http_executor.py
+17
-2
http_request_node.py
api/core/workflow/nodes/http_request/http_request_node.py
+6
-4
http.py
api/tests/integration_tests/workflow/nodes/__mock/http.py
+9
-6
test_http.py
api/tests/integration_tests/workflow/nodes/test_http.py
+165
-7
No files found.
api/core/helper/ssrf_proxy.py
View file @
2008986f
...
...
@@ -26,7 +26,6 @@ httpx_proxies = {
}
if
SSRF_PROXY_HTTP_URL
and
SSRF_PROXY_HTTPS_URL
else
None
def
get
(
url
,
*
args
,
**
kwargs
):
print
(
url
,
kwargs
)
return
_get
(
url
=
url
,
*
args
,
proxies
=
httpx_proxies
,
**
kwargs
)
def
post
(
url
,
*
args
,
**
kwargs
):
...
...
api/core/workflow/nodes/http_request/http_executor.py
View file @
2008986f
...
...
@@ -43,6 +43,7 @@ class HttpExecutor:
self
.
params
=
{}
self
.
headers
=
{}
self
.
body
=
None
self
.
files
=
None
# init template
self
.
_init_template
(
node_data
,
variables
)
...
...
@@ -248,10 +249,24 @@ class HttpExecutor:
server_url
+=
f
'?{urlencode(self.params)}'
raw_request
=
f
'{self.method.upper()} {server_url} HTTP/1.1
\n
'
for
k
,
v
in
self
.
headers
.
items
():
headers
=
self
.
_assembling_headers
()
for
k
,
v
in
headers
.
items
():
raw_request
+=
f
'{k}: {v}
\n
'
raw_request
+=
'
\n
'
raw_request
+=
self
.
body
or
''
# if files, use multipart/form-data with boundary
if
self
.
files
:
boundary
=
'----WebKitFormBoundary7MA4YWxkTrZu0gW'
raw_request
=
f
'--{boundary}
\n
'
+
raw_request
for
k
,
v
in
self
.
files
.
items
():
raw_request
+=
f
'Content-Disposition: form-data; name="{k}"; filename="{v[0]}"
\n
'
raw_request
+=
f
'Content-Type: {v[1]}
\n\n
'
raw_request
+=
v
[
1
]
+
'
\n
'
raw_request
+=
f
'--{boundary}
\n
'
raw_request
+=
'--
\n
'
else
:
raw_request
+=
self
.
body
or
''
return
raw_request
\ No newline at end of file
api/core/workflow/nodes/http_request/http_request_node.py
View file @
2008986f
...
...
@@ -28,13 +28,13 @@ class HttpRequestNode(BaseNode):
# invoke http executor
response
=
http_executor
.
invoke
()
except
Exception
as
e
:
import
traceback
print
(
traceback
.
format_exc
())
return
NodeRunResult
(
status
=
WorkflowNodeExecutionStatus
.
FAILED
,
inputs
=
variables
,
error
=
str
(
e
),
process_data
=
http_executor
.
to_raw_request
()
process_data
=
{
'request'
:
http_executor
.
to_raw_request
()
}
)
return
NodeRunResult
(
...
...
@@ -45,7 +45,9 @@ class HttpRequestNode(BaseNode):
'body'
:
response
,
'headers'
:
response
.
headers
},
process_data
=
http_executor
.
to_raw_request
()
process_data
=
{
'request'
:
http_executor
.
to_raw_request
(),
}
)
...
...
api/tests/integration_tests/workflow/nodes/__mock/http.py
View file @
2008986f
...
...
@@ -3,6 +3,7 @@ import pytest
import
requests.api
as
requests
import
httpx._api
as
httpx
from
requests
import
Response
as
RequestsResponse
from
httpx
import
Request
as
HttpxRequest
from
yarl
import
URL
from
typing
import
Literal
...
...
@@ -12,8 +13,8 @@ from json import dumps
MOCK
=
os
.
getenv
(
'MOCK_SWITCH'
,
'false'
)
==
'true'
class
MockedHttp
:
def
requests_request
(
self
,
method
:
Literal
[
'GET'
,
'POST'
,
'PUT'
,
'DELETE'
,
'PATCH'
,
'OPTIONS'
],
url
:
str
,
**
kwargs
)
->
RequestsResponse
:
def
requests_request
(
method
:
Literal
[
'GET'
,
'POST'
,
'PUT'
,
'DELETE'
,
'PATCH'
,
'OPTIONS'
],
url
:
str
,
**
kwargs
)
->
RequestsResponse
:
"""
Mocked requests.request
"""
...
...
@@ -41,13 +42,15 @@ class MockedHttp:
response
.
_content
=
resp
return
response
def
httpx_request
(
self
,
method
:
Literal
[
'GET'
,
'POST'
,
'PUT'
,
'DELETE'
,
'PATCH'
,
'OPTIONS'
],
def
httpx_request
(
method
:
Literal
[
'GET'
,
'POST'
,
'PUT'
,
'DELETE'
,
'PATCH'
,
'OPTIONS'
],
url
:
str
,
**
kwargs
)
->
httpx
.
Response
:
"""
Mocked httpx.request
"""
response
=
httpx
.
Response
()
response
.
url
=
str
(
URL
(
url
)
%
kwargs
.
get
(
'params'
,
{}))
response
=
httpx
.
Response
(
status_code
=
200
,
request
=
HttpxRequest
(
method
,
url
)
)
response
.
headers
=
kwargs
.
get
(
'headers'
,
{})
if
url
==
'http://404.com'
:
...
...
@@ -67,7 +70,7 @@ class MockedHttp:
resp
=
b
'OK'
response
.
status_code
=
200
response
.
content
=
resp
response
.
_
content
=
resp
return
response
@
pytest
.
fixture
...
...
api/tests/integration_tests/workflow/nodes/test_http.py
View file @
2008986f
...
...
@@ -2,7 +2,6 @@ from calendar import c
import
pytest
from
core.app.entities.app_invoke_entities
import
InvokeFrom
from
core.workflow.entities.variable_pool
import
VariablePool
from
core.workflow.nodes.http_request.entities
import
HttpRequestNodeData
from
core.workflow.nodes.http_request.http_request_node
import
HttpRequestNode
from
tests.integration_tests.workflow.nodes.__mock.http
import
setup_http_mock
...
...
@@ -21,13 +20,16 @@ pool.append_variable(node_id='1', variable_key_list=['123', 'args1'], value=1)
pool
.
append_variable
(
node_id
=
'1'
,
variable_key_list
=
[
'123'
,
'args2'
],
value
=
2
)
@
pytest
.
mark
.
parametrize
(
'setup_http_mock'
,
[[
'none'
]],
indirect
=
True
)
def
test_get
_param
(
setup_http_mock
):
def
test_get
(
setup_http_mock
):
node
=
HttpRequestNode
(
config
=
{
'id'
:
'1'
,
'data'
:
{
'title'
:
'http'
,
'desc'
:
''
,
'variables'
:
[],
'variables'
:
[{
'variable'
:
'args1'
,
'value_selector'
:
[
'1'
,
'123'
,
'args1'
],
}],
'method'
:
'get'
,
'url'
:
'http://example.com'
,
'authorization'
:
{
...
...
@@ -38,14 +40,170 @@ def test_get_param(setup_http_mock):
'header'
:
'api-key'
,
}
},
'headers'
:
''
,
'params'
:
''
,
'headers'
:
'
X-Header:123
'
,
'params'
:
'
A:b
'
,
'body'
:
None
,
}
},
**
BASIC_NODE_DATA
)
result
=
node
.
run
(
pool
)
print
(
result
)
data
=
result
.
process_data
.
get
(
'request'
,
''
)
assert
1
==
2
\ No newline at end of file
assert
'?A=b'
in
data
assert
'api-key: Basic ak-xxx'
in
data
assert
'X-Header: 123'
in
data
@
pytest
.
mark
.
parametrize
(
'setup_http_mock'
,
[[
'none'
]],
indirect
=
True
)
def
test_template
(
setup_http_mock
):
node
=
HttpRequestNode
(
config
=
{
'id'
:
'1'
,
'data'
:
{
'title'
:
'http'
,
'desc'
:
''
,
'variables'
:
[{
'variable'
:
'args1'
,
'value_selector'
:
[
'1'
,
'123'
,
'args2'
],
}],
'method'
:
'get'
,
'url'
:
'http://example.com/{{args1}}'
,
'authorization'
:
{
'type'
:
'api-key'
,
'config'
:
{
'type'
:
'basic'
,
'api_key'
:
'ak-xxx'
,
'header'
:
'api-key'
,
}
},
'headers'
:
'X-Header:123
\n
X-Header2:{{args1}}'
,
'params'
:
'A:b
\n
Template:{{args1}}'
,
'body'
:
None
,
}
},
**
BASIC_NODE_DATA
)
result
=
node
.
run
(
pool
)
data
=
result
.
process_data
.
get
(
'request'
,
''
)
assert
'?A=b'
in
data
assert
'Template=2'
in
data
assert
'api-key: Basic ak-xxx'
in
data
assert
'X-Header: 123'
in
data
assert
'X-Header2: 2'
in
data
@
pytest
.
mark
.
parametrize
(
'setup_http_mock'
,
[[
'none'
]],
indirect
=
True
)
def
test_json
(
setup_http_mock
):
node
=
HttpRequestNode
(
config
=
{
'id'
:
'1'
,
'data'
:
{
'title'
:
'http'
,
'desc'
:
''
,
'variables'
:
[{
'variable'
:
'args1'
,
'value_selector'
:
[
'1'
,
'123'
,
'args1'
],
}],
'method'
:
'post'
,
'url'
:
'http://example.com'
,
'authorization'
:
{
'type'
:
'api-key'
,
'config'
:
{
'type'
:
'basic'
,
'api_key'
:
'ak-xxx'
,
'header'
:
'api-key'
,
}
},
'headers'
:
'X-Header:123'
,
'params'
:
'A:b'
,
'body'
:
{
'type'
:
'json'
,
'data'
:
'{"a": "{{args1}}"}'
},
}
},
**
BASIC_NODE_DATA
)
result
=
node
.
run
(
pool
)
data
=
result
.
process_data
.
get
(
'request'
,
''
)
assert
'{"a": "1"}'
in
data
assert
'api-key: Basic ak-xxx'
in
data
assert
'X-Header: 123'
in
data
def
test_x_www_form_urlencoded
(
setup_http_mock
):
node
=
HttpRequestNode
(
config
=
{
'id'
:
'1'
,
'data'
:
{
'title'
:
'http'
,
'desc'
:
''
,
'variables'
:
[{
'variable'
:
'args1'
,
'value_selector'
:
[
'1'
,
'123'
,
'args1'
],
},
{
'variable'
:
'args2'
,
'value_selector'
:
[
'1'
,
'123'
,
'args2'
],
}],
'method'
:
'post'
,
'url'
:
'http://example.com'
,
'authorization'
:
{
'type'
:
'api-key'
,
'config'
:
{
'type'
:
'basic'
,
'api_key'
:
'ak-xxx'
,
'header'
:
'api-key'
,
}
},
'headers'
:
'X-Header:123'
,
'params'
:
'A:b'
,
'body'
:
{
'type'
:
'x-www-form-urlencoded'
,
'data'
:
'a:{{args1}}
\n
b:{{args2}}'
},
}
},
**
BASIC_NODE_DATA
)
result
=
node
.
run
(
pool
)
data
=
result
.
process_data
.
get
(
'request'
,
''
)
assert
'a=1&b=2'
in
data
assert
'api-key: Basic ak-xxx'
in
data
assert
'X-Header: 123'
in
data
def
test_form_data
(
setup_http_mock
):
node
=
HttpRequestNode
(
config
=
{
'id'
:
'1'
,
'data'
:
{
'title'
:
'http'
,
'desc'
:
''
,
'variables'
:
[{
'variable'
:
'args1'
,
'value_selector'
:
[
'1'
,
'123'
,
'args1'
],
},
{
'variable'
:
'args2'
,
'value_selector'
:
[
'1'
,
'123'
,
'args2'
],
}],
'method'
:
'post'
,
'url'
:
'http://example.com'
,
'authorization'
:
{
'type'
:
'api-key'
,
'config'
:
{
'type'
:
'basic'
,
'api_key'
:
'ak-xxx'
,
'header'
:
'api-key'
,
}
},
'headers'
:
'X-Header:123'
,
'params'
:
'A:b'
,
'body'
:
{
'type'
:
'form-data'
,
'data'
:
'a:{{args1}}
\n
b:{{args2}}'
},
}
},
**
BASIC_NODE_DATA
)
result
=
node
.
run
(
pool
)
data
=
result
.
process_data
.
get
(
'request'
,
''
)
assert
'form-data; name="a"'
in
data
assert
'1'
in
data
assert
'form-data; name="b"'
in
data
assert
'2'
in
data
assert
'api-key: Basic ak-xxx'
in
data
assert
'X-Header: 123'
in
data
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment