Compare commits

...

4 Commits

Author SHA1 Message Date
autofix-ci[bot]
0bdde84a3e [autofix.ci] apply automated fixes 2026-02-16 15:46:53 +00:00
-LAN-
2d5f1178ea chore: reconcile remote config branch after rebasing main
# Conflicts:
#	api/core/app/workflow/node_factory.py
2026-02-16 23:45:07 +08:00
-LAN-
b9cbf0fdce refactor(workflow): inject http request node config through factories and defaults 2026-02-16 23:44:27 +08:00
-LAN-
98c39b0d6c refactor(workflow): inject http request node config through factories and defaults 2026-02-16 22:42:07 +08:00
12 changed files with 199 additions and 44 deletions

View File

@@ -115,9 +115,6 @@ ignore_imports =
core.workflow.nodes.datasource.datasource_node -> models.tools
core.workflow.nodes.datasource.datasource_node -> services.datasource_provider_service
core.workflow.nodes.document_extractor.node -> core.helper.ssrf_proxy
core.workflow.nodes.http_request.entities -> configs
core.workflow.nodes.http_request.executor -> configs
core.workflow.nodes.http_request.node -> configs
core.workflow.nodes.http_request.node -> core.tools.tool_file_manager
core.workflow.nodes.iteration.iteration_node -> core.app.workflow.node_factory
core.workflow.nodes.knowledge_index.knowledge_index_node -> core.rag.index_processor.index_processor_factory

View File

@@ -17,7 +17,7 @@ from core.workflow.nodes.base.node import Node
from core.workflow.nodes.code.code_node import CodeNode
from core.workflow.nodes.code.limits import CodeNodeLimits
from core.workflow.nodes.document_extractor import DocumentExtractorNode, UnstructuredApiConfig
from core.workflow.nodes.http_request.node import HttpRequestNode
from core.workflow.nodes.http_request import HttpRequestNode, HttpRequestNodeConfig
from core.workflow.nodes.knowledge_retrieval.knowledge_retrieval_node import KnowledgeRetrievalNode
from core.workflow.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING
from core.workflow.nodes.protocols import FileManagerProtocol, HttpClientProtocol
@@ -45,6 +45,7 @@ class DifyNodeFactory(NodeFactory):
self,
graph_init_params: "GraphInitParams",
graph_runtime_state: "GraphRuntimeState",
*,
code_executor: type[CodeExecutor] | None = None,
code_providers: Sequence[type[CodeNodeProvider]] | None = None,
code_limits: CodeNodeLimits | None = None,
@@ -54,6 +55,7 @@ class DifyNodeFactory(NodeFactory):
http_request_tool_file_manager_factory: Callable[[], ToolFileManager] = ToolFileManager,
http_request_file_manager: FileManagerProtocol | None = None,
document_extractor_unstructured_api_config: UnstructuredApiConfig | None = None,
http_request_config: HttpRequestNodeConfig | None = None,
) -> None:
self.graph_init_params = graph_init_params
self.graph_runtime_state = graph_runtime_state
@@ -86,6 +88,15 @@ class DifyNodeFactory(NodeFactory):
api_key=dify_config.UNSTRUCTURED_API_KEY or "",
)
)
self._http_request_config = http_request_config or HttpRequestNodeConfig(
max_connect_timeout=dify_config.HTTP_REQUEST_MAX_CONNECT_TIMEOUT,
max_read_timeout=dify_config.HTTP_REQUEST_MAX_READ_TIMEOUT,
max_write_timeout=dify_config.HTTP_REQUEST_MAX_WRITE_TIMEOUT,
max_binary_size=dify_config.HTTP_REQUEST_NODE_MAX_BINARY_SIZE,
max_text_size=dify_config.HTTP_REQUEST_NODE_MAX_TEXT_SIZE,
ssl_verify=dify_config.HTTP_REQUEST_NODE_SSL_VERIFY,
ssrf_default_max_retries=dify_config.SSRF_DEFAULT_MAX_RETRIES,
)
@override
def create_node(self, node_config: NodeConfigDict) -> Node:
@@ -146,6 +157,7 @@ class DifyNodeFactory(NodeFactory):
config=node_config,
graph_init_params=self.graph_init_params,
graph_runtime_state=self.graph_runtime_state,
http_request_config=self._http_request_config,
http_client=self._http_request_http_client,
tool_file_manager_factory=self._http_request_tool_file_manager_factory,
file_manager=self._http_request_file_manager,

View File

@@ -1,4 +1,19 @@
from .entities import BodyData, HttpRequestNodeAuthorization, HttpRequestNodeBody, HttpRequestNodeData
from .entities import (
HTTP_REQUEST_CONFIG_FILTER_KEY,
BodyData,
HttpRequestNodeAuthorization,
HttpRequestNodeBody,
HttpRequestNodeConfig,
HttpRequestNodeData,
)
from .node import HttpRequestNode
__all__ = ["BodyData", "HttpRequestNode", "HttpRequestNodeAuthorization", "HttpRequestNodeBody", "HttpRequestNodeData"]
__all__ = [
"HTTP_REQUEST_CONFIG_FILTER_KEY",
"BodyData",
"HttpRequestNode",
"HttpRequestNodeAuthorization",
"HttpRequestNodeBody",
"HttpRequestNodeConfig",
"HttpRequestNodeData",
]

View File

@@ -1,5 +1,6 @@
import mimetypes
from collections.abc import Sequence
from dataclasses import dataclass
from email.message import Message
from typing import Any, Literal
@@ -7,9 +8,10 @@ import charset_normalizer
import httpx
from pydantic import BaseModel, Field, ValidationInfo, field_validator
from configs import dify_config
from core.workflow.nodes.base import BaseNodeData
HTTP_REQUEST_CONFIG_FILTER_KEY = "http_request_config"
class HttpRequestNodeAuthorizationConfig(BaseModel):
type: Literal["basic", "bearer", "custom"]
@@ -59,9 +61,27 @@ class HttpRequestNodeBody(BaseModel):
class HttpRequestNodeTimeout(BaseModel):
connect: int = dify_config.HTTP_REQUEST_MAX_CONNECT_TIMEOUT
read: int = dify_config.HTTP_REQUEST_MAX_READ_TIMEOUT
write: int = dify_config.HTTP_REQUEST_MAX_WRITE_TIMEOUT
connect: int | None = None
read: int | None = None
write: int | None = None
@dataclass(frozen=True, slots=True)
class HttpRequestNodeConfig:
max_connect_timeout: int
max_read_timeout: int
max_write_timeout: int
max_binary_size: int
max_text_size: int
ssl_verify: bool
ssrf_default_max_retries: int
def default_timeout(self) -> "HttpRequestNodeTimeout":
return HttpRequestNodeTimeout(
connect=self.max_connect_timeout,
read=self.max_read_timeout,
write=self.max_write_timeout,
)
class HttpRequestNodeData(BaseNodeData):
@@ -91,7 +111,7 @@ class HttpRequestNodeData(BaseNodeData):
params: str
body: HttpRequestNodeBody | None = None
timeout: HttpRequestNodeTimeout | None = None
ssl_verify: bool | None = dify_config.HTTP_REQUEST_NODE_SSL_VERIFY
ssl_verify: bool | None = None
class Response:

View File

@@ -10,7 +10,6 @@ from urllib.parse import urlencode, urlparse
import httpx
from json_repair import repair_json
from configs import dify_config
from core.helper.ssrf_proxy import ssrf_proxy
from core.variables.segments import ArrayFileSegment, FileSegment
from core.workflow.file.enums import FileTransferMethod
@@ -20,6 +19,7 @@ from core.workflow.runtime import VariablePool
from ..protocols import FileManagerProtocol, HttpClientProtocol
from .entities import (
HttpRequestNodeAuthorization,
HttpRequestNodeConfig,
HttpRequestNodeData,
HttpRequestNodeTimeout,
Response,
@@ -78,10 +78,13 @@ class Executor:
node_data: HttpRequestNodeData,
timeout: HttpRequestNodeTimeout,
variable_pool: VariablePool,
max_retries: int = dify_config.SSRF_DEFAULT_MAX_RETRIES,
http_request_config: HttpRequestNodeConfig,
max_retries: int | None = None,
ssl_verify: bool | None = None,
http_client: HttpClientProtocol | None = None,
file_manager: FileManagerProtocol | None = None,
):
self._http_request_config = http_request_config
# If authorization API key is present, convert the API key using the variable pool
if node_data.authorization.type == "api-key":
if node_data.authorization.config is None:
@@ -99,14 +102,21 @@ class Executor:
self.method = node_data.method
self.auth = node_data.authorization
self.timeout = timeout
self.ssl_verify = node_data.ssl_verify
resolved_ssl_verify = ssl_verify if ssl_verify is not None else node_data.ssl_verify
if resolved_ssl_verify is None:
resolved_ssl_verify = self._http_request_config.ssl_verify
if not isinstance(resolved_ssl_verify, bool):
raise ValueError("ssl_verify must be a boolean")
self.ssl_verify = resolved_ssl_verify
self.params = None
self.headers = {}
self.content = None
self.files = None
self.data = None
self.json = None
self.max_retries = max_retries
self.max_retries = (
max_retries if max_retries is not None else self._http_request_config.ssrf_default_max_retries
)
self._http_client = http_client or ssrf_proxy
self._file_manager = file_manager or default_file_manager
@@ -319,9 +329,9 @@ class Executor:
executor_response = Response(response)
threshold_size = (
dify_config.HTTP_REQUEST_NODE_MAX_BINARY_SIZE
self._http_request_config.max_binary_size
if executor_response.is_file
else dify_config.HTTP_REQUEST_NODE_MAX_TEXT_SIZE
else self._http_request_config.max_text_size
)
if executor_response.size > threshold_size:
raise ResponseSizeError(

View File

@@ -3,7 +3,6 @@ import mimetypes
from collections.abc import Callable, Mapping, Sequence
from typing import TYPE_CHECKING, Any
from configs import dify_config
from core.helper.ssrf_proxy import ssrf_proxy
from core.tools.tool_file_manager import ToolFileManager
from core.variables.segments import ArrayFileSegment
@@ -19,18 +18,14 @@ from core.workflow.nodes.protocols import FileManagerProtocol, HttpClientProtoco
from factories import file_factory
from .entities import (
HTTP_REQUEST_CONFIG_FILTER_KEY,
HttpRequestNodeConfig,
HttpRequestNodeData,
HttpRequestNodeTimeout,
Response,
)
from .exc import HttpRequestNodeError, RequestBodyError
HTTP_REQUEST_DEFAULT_TIMEOUT = HttpRequestNodeTimeout(
connect=dify_config.HTTP_REQUEST_MAX_CONNECT_TIMEOUT,
read=dify_config.HTTP_REQUEST_MAX_READ_TIMEOUT,
write=dify_config.HTTP_REQUEST_MAX_WRITE_TIMEOUT,
)
logger = logging.getLogger(__name__)
if TYPE_CHECKING:
@@ -38,6 +33,15 @@ if TYPE_CHECKING:
from core.workflow.runtime import GraphRuntimeState
def _resolve_http_request_config(filters: Mapping[str, object] | None) -> HttpRequestNodeConfig:
if not filters:
raise ValueError("http_request_config is required to build HTTP request default config")
config = filters.get(HTTP_REQUEST_CONFIG_FILTER_KEY)
if not isinstance(config, HttpRequestNodeConfig):
raise ValueError("http_request_config must be an HttpRequestNodeConfig instance")
return config
class HttpRequestNode(Node[HttpRequestNodeData]):
node_type = NodeType.HTTP_REQUEST
@@ -48,6 +52,7 @@ class HttpRequestNode(Node[HttpRequestNodeData]):
graph_init_params: "GraphInitParams",
graph_runtime_state: "GraphRuntimeState",
*,
http_request_config: HttpRequestNodeConfig,
http_client: HttpClientProtocol | None = None,
tool_file_manager_factory: Callable[[], ToolFileManager] = ToolFileManager,
file_manager: FileManagerProtocol | None = None,
@@ -58,12 +63,15 @@ class HttpRequestNode(Node[HttpRequestNodeData]):
graph_init_params=graph_init_params,
graph_runtime_state=graph_runtime_state,
)
self._http_request_config = http_request_config
self._http_client = http_client or ssrf_proxy
self._tool_file_manager_factory = tool_file_manager_factory
self._file_manager = file_manager or default_file_manager
@classmethod
def get_default_config(cls, filters: Mapping[str, object] | None = None) -> Mapping[str, object]:
http_request_config = _resolve_http_request_config(filters)
default_timeout = http_request_config.default_timeout()
return {
"type": "http-request",
"config": {
@@ -73,15 +81,15 @@ class HttpRequestNode(Node[HttpRequestNodeData]):
},
"body": {"type": "none"},
"timeout": {
**HTTP_REQUEST_DEFAULT_TIMEOUT.model_dump(),
"max_connect_timeout": dify_config.HTTP_REQUEST_MAX_CONNECT_TIMEOUT,
"max_read_timeout": dify_config.HTTP_REQUEST_MAX_READ_TIMEOUT,
"max_write_timeout": dify_config.HTTP_REQUEST_MAX_WRITE_TIMEOUT,
**default_timeout.model_dump(),
"max_connect_timeout": http_request_config.max_connect_timeout,
"max_read_timeout": http_request_config.max_read_timeout,
"max_write_timeout": http_request_config.max_write_timeout,
},
"ssl_verify": dify_config.HTTP_REQUEST_NODE_SSL_VERIFY,
"ssl_verify": http_request_config.ssl_verify,
},
"retry_config": {
"max_retries": dify_config.SSRF_DEFAULT_MAX_RETRIES,
"max_retries": http_request_config.ssrf_default_max_retries,
"retry_interval": 0.5 * (2**2),
"retry_enabled": True,
},
@@ -98,7 +106,9 @@ class HttpRequestNode(Node[HttpRequestNodeData]):
node_data=self.node_data,
timeout=self._get_request_timeout(self.node_data),
variable_pool=self.graph_runtime_state.variable_pool,
http_request_config=self._http_request_config,
max_retries=0,
ssl_verify=self._resolve_ssl_verify(self.node_data),
http_client=self._http_client,
file_manager=self._file_manager,
)
@@ -142,15 +152,18 @@ class HttpRequestNode(Node[HttpRequestNodeData]):
error_type=type(e).__name__,
)
@staticmethod
def _get_request_timeout(node_data: HttpRequestNodeData) -> HttpRequestNodeTimeout:
def _resolve_ssl_verify(self, node_data: HttpRequestNodeData) -> bool:
return self._http_request_config.ssl_verify if node_data.ssl_verify is None else node_data.ssl_verify
def _get_request_timeout(self, node_data: HttpRequestNodeData) -> HttpRequestNodeTimeout:
default_timeout = self._http_request_config.default_timeout()
timeout = node_data.timeout
if timeout is None:
return HTTP_REQUEST_DEFAULT_TIMEOUT
return default_timeout
timeout.connect = timeout.connect or HTTP_REQUEST_DEFAULT_TIMEOUT.connect
timeout.read = timeout.read or HTTP_REQUEST_DEFAULT_TIMEOUT.read
timeout.write = timeout.write or HTTP_REQUEST_DEFAULT_TIMEOUT.write
timeout.connect = timeout.connect or default_timeout.connect
timeout.read = timeout.read or default_timeout.read
timeout.write = timeout.write or default_timeout.write
return timeout
@classmethod

View File

@@ -47,6 +47,7 @@ from core.workflow.graph_events import NodeRunFailedEvent, NodeRunSucceededEvent
from core.workflow.graph_events.base import GraphNodeEventBase
from core.workflow.node_events.base import NodeRunResult
from core.workflow.nodes.base.node import Node
from core.workflow.nodes.http_request import HTTP_REQUEST_CONFIG_FILTER_KEY, HttpRequestNodeConfig
from core.workflow.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING
from core.workflow.repositories.workflow_node_execution_repository import OrderConfig
from core.workflow.runtime import VariablePool
@@ -86,6 +87,18 @@ from services.workflow_draft_variable_service import DraftVariableSaver, DraftVa
logger = logging.getLogger(__name__)
def _build_http_request_config() -> HttpRequestNodeConfig:
return HttpRequestNodeConfig(
max_connect_timeout=dify_config.HTTP_REQUEST_MAX_CONNECT_TIMEOUT,
max_read_timeout=dify_config.HTTP_REQUEST_MAX_READ_TIMEOUT,
max_write_timeout=dify_config.HTTP_REQUEST_MAX_WRITE_TIMEOUT,
max_binary_size=dify_config.HTTP_REQUEST_NODE_MAX_BINARY_SIZE,
max_text_size=dify_config.HTTP_REQUEST_NODE_MAX_TEXT_SIZE,
ssl_verify=dify_config.HTTP_REQUEST_NODE_SSL_VERIFY,
ssrf_default_max_retries=dify_config.SSRF_DEFAULT_MAX_RETRIES,
)
class RagPipelineService:
def __init__(self, session_maker: sessionmaker | None = None):
"""Initialize RagPipelineService with repository dependencies."""
@@ -380,9 +393,12 @@ class RagPipelineService:
"""
# return default block config
default_block_configs: list[dict[str, Any]] = []
for node_class_mapping in NODE_TYPE_CLASSES_MAPPING.values():
for node_type, node_class_mapping in NODE_TYPE_CLASSES_MAPPING.items():
node_class = node_class_mapping[LATEST_VERSION]
default_config = node_class.get_default_config()
filters = None
if node_type is NodeType.HTTP_REQUEST:
filters = {HTTP_REQUEST_CONFIG_FILTER_KEY: _build_http_request_config()}
default_config = node_class.get_default_config(filters=filters)
if default_config:
default_block_configs.append(dict(default_config))
@@ -402,7 +418,10 @@ class RagPipelineService:
return None
node_class = NODE_TYPE_CLASSES_MAPPING[node_type_enum][LATEST_VERSION]
default_config = node_class.get_default_config(filters=filters)
resolved_filters = dict(filters) if filters else {}
if node_type_enum is NodeType.HTTP_REQUEST and HTTP_REQUEST_CONFIG_FILTER_KEY not in resolved_filters:
resolved_filters[HTTP_REQUEST_CONFIG_FILTER_KEY] = _build_http_request_config()
default_config = node_class.get_default_config(filters=resolved_filters or None)
if not default_config:
return None

View File

@@ -26,6 +26,7 @@ from core.workflow.graph_events import GraphNodeEventBase, NodeRunFailedEvent, N
from core.workflow.node_events import NodeRunResult
from core.workflow.nodes import NodeType
from core.workflow.nodes.base.node import Node
from core.workflow.nodes.http_request import HTTP_REQUEST_CONFIG_FILTER_KEY, HttpRequestNodeConfig
from core.workflow.nodes.human_input.entities import (
DeliveryChannelConfig,
HumanInputNodeData,
@@ -70,6 +71,18 @@ from .human_input_delivery_test_service import (
from .workflow_draft_variable_service import DraftVariableSaver, DraftVarLoader, WorkflowDraftVariableService
def _build_http_request_config() -> HttpRequestNodeConfig:
return HttpRequestNodeConfig(
max_connect_timeout=dify_config.HTTP_REQUEST_MAX_CONNECT_TIMEOUT,
max_read_timeout=dify_config.HTTP_REQUEST_MAX_READ_TIMEOUT,
max_write_timeout=dify_config.HTTP_REQUEST_MAX_WRITE_TIMEOUT,
max_binary_size=dify_config.HTTP_REQUEST_NODE_MAX_BINARY_SIZE,
max_text_size=dify_config.HTTP_REQUEST_NODE_MAX_TEXT_SIZE,
ssl_verify=dify_config.HTTP_REQUEST_NODE_SSL_VERIFY,
ssrf_default_max_retries=dify_config.SSRF_DEFAULT_MAX_RETRIES,
)
class WorkflowService:
"""
Workflow Service
@@ -618,9 +631,12 @@ class WorkflowService:
"""
# return default block config
default_block_configs: list[Mapping[str, object]] = []
for node_class_mapping in NODE_TYPE_CLASSES_MAPPING.values():
for node_type, node_class_mapping in NODE_TYPE_CLASSES_MAPPING.items():
node_class = node_class_mapping[LATEST_VERSION]
default_config = node_class.get_default_config()
filters = None
if node_type is NodeType.HTTP_REQUEST:
filters = {HTTP_REQUEST_CONFIG_FILTER_KEY: _build_http_request_config()}
default_config = node_class.get_default_config(filters=filters)
if default_config:
default_block_configs.append(default_config)
@@ -642,7 +658,10 @@ class WorkflowService:
return {}
node_class = NODE_TYPE_CLASSES_MAPPING[node_type_enum][LATEST_VERSION]
default_config = node_class.get_default_config(filters=filters)
resolved_filters = dict(filters) if filters else {}
if node_type_enum is NodeType.HTTP_REQUEST and HTTP_REQUEST_CONFIG_FILTER_KEY not in resolved_filters:
resolved_filters[HTTP_REQUEST_CONFIG_FILTER_KEY] = _build_http_request_config()
default_config = node_class.get_default_config(filters=resolved_filters or None)
if not default_config:
return {}

View File

@@ -4,17 +4,28 @@ from urllib.parse import urlencode
import pytest
from configs import dify_config
from core.app.entities.app_invoke_entities import InvokeFrom
from core.app.workflow.node_factory import DifyNodeFactory
from core.workflow.entities import GraphInitParams
from core.workflow.enums import WorkflowNodeExecutionStatus
from core.workflow.graph import Graph
from core.workflow.nodes.http_request.node import HttpRequestNode
from core.workflow.nodes.http_request import HttpRequestNode, HttpRequestNodeConfig
from core.workflow.runtime import GraphRuntimeState, VariablePool
from core.workflow.system_variable import SystemVariable
from models.enums import UserFrom
from tests.integration_tests.workflow.nodes.__mock.http import setup_http_mock
HTTP_REQUEST_CONFIG = HttpRequestNodeConfig(
max_connect_timeout=dify_config.HTTP_REQUEST_MAX_CONNECT_TIMEOUT,
max_read_timeout=dify_config.HTTP_REQUEST_MAX_READ_TIMEOUT,
max_write_timeout=dify_config.HTTP_REQUEST_MAX_WRITE_TIMEOUT,
max_binary_size=dify_config.HTTP_REQUEST_NODE_MAX_BINARY_SIZE,
max_text_size=dify_config.HTTP_REQUEST_NODE_MAX_TEXT_SIZE,
ssl_verify=dify_config.HTTP_REQUEST_NODE_SSL_VERIFY,
ssrf_default_max_retries=dify_config.SSRF_DEFAULT_MAX_RETRIES,
)
def init_http_node(config: dict):
graph_config = {
@@ -64,6 +75,7 @@ def init_http_node(config: dict):
config=config,
graph_init_params=init_params,
graph_runtime_state=graph_runtime_state,
http_request_config=HTTP_REQUEST_CONFIG,
)
return node
@@ -215,6 +227,7 @@ def test_custom_auth_with_empty_api_key_raises_error(setup_http_mock):
Executor(
node_data=node_data,
timeout=HttpRequestNodeTimeout(connect=10, read=30, write=10),
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -702,6 +715,7 @@ def test_nested_object_variable_selector(setup_http_mock):
config=graph_config["nodes"][1],
graph_init_params=init_params,
graph_runtime_state=graph_runtime_state,
http_request_config=HTTP_REQUEST_CONFIG,
)
result = node._run()

View File

@@ -114,6 +114,15 @@ class MockNodeFactory(DifyNodeFactory):
code_providers=self._code_providers,
code_limits=self._code_limits,
)
elif node_type == NodeType.HTTP_REQUEST:
mock_instance = mock_class(
id=node_id,
config=node_config,
graph_init_params=self.graph_init_params,
graph_runtime_state=self.graph_runtime_state,
mock_config=self.mock_config,
http_request_config=self._http_request_config,
)
else:
mock_instance = mock_class(
id=node_id,

View File

@@ -1,9 +1,11 @@
import pytest
from configs import dify_config
from core.workflow.nodes.http_request import (
BodyData,
HttpRequestNodeAuthorization,
HttpRequestNodeBody,
HttpRequestNodeConfig,
HttpRequestNodeData,
)
from core.workflow.nodes.http_request.entities import HttpRequestNodeTimeout
@@ -12,6 +14,16 @@ from core.workflow.nodes.http_request.executor import Executor
from core.workflow.runtime import VariablePool
from core.workflow.system_variable import SystemVariable
HTTP_REQUEST_CONFIG = HttpRequestNodeConfig(
max_connect_timeout=dify_config.HTTP_REQUEST_MAX_CONNECT_TIMEOUT,
max_read_timeout=dify_config.HTTP_REQUEST_MAX_READ_TIMEOUT,
max_write_timeout=dify_config.HTTP_REQUEST_MAX_WRITE_TIMEOUT,
max_binary_size=dify_config.HTTP_REQUEST_NODE_MAX_BINARY_SIZE,
max_text_size=dify_config.HTTP_REQUEST_NODE_MAX_TEXT_SIZE,
ssl_verify=dify_config.HTTP_REQUEST_NODE_SSL_VERIFY,
ssrf_default_max_retries=dify_config.SSRF_DEFAULT_MAX_RETRIES,
)
def test_executor_with_json_body_and_number_variable():
# Prepare the variable pool
@@ -45,6 +57,7 @@ def test_executor_with_json_body_and_number_variable():
executor = Executor(
node_data=node_data,
timeout=HttpRequestNodeTimeout(connect=10, read=30, write=30),
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -98,6 +111,7 @@ def test_executor_with_json_body_and_object_variable():
executor = Executor(
node_data=node_data,
timeout=HttpRequestNodeTimeout(connect=10, read=30, write=30),
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -153,6 +167,7 @@ def test_executor_with_json_body_and_nested_object_variable():
executor = Executor(
node_data=node_data,
timeout=HttpRequestNodeTimeout(connect=10, read=30, write=30),
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -196,6 +211,7 @@ def test_extract_selectors_from_template_with_newline():
executor = Executor(
node_data=node_data,
timeout=HttpRequestNodeTimeout(connect=10, read=30, write=30),
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -240,6 +256,7 @@ def test_executor_with_form_data():
executor = Executor(
node_data=node_data,
timeout=HttpRequestNodeTimeout(connect=10, read=30, write=30),
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -290,6 +307,7 @@ def test_init_headers():
return Executor(
node_data=node_data,
timeout=timeout,
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=VariablePool(system_variables=SystemVariable.default()),
)
@@ -324,6 +342,7 @@ def test_init_params():
return Executor(
node_data=node_data,
timeout=timeout,
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=VariablePool(system_variables=SystemVariable.default()),
)
@@ -373,6 +392,7 @@ def test_empty_api_key_raises_error_bearer():
Executor(
node_data=node_data,
timeout=timeout,
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -397,6 +417,7 @@ def test_empty_api_key_raises_error_basic():
Executor(
node_data=node_data,
timeout=timeout,
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -421,6 +442,7 @@ def test_empty_api_key_raises_error_custom():
Executor(
node_data=node_data,
timeout=timeout,
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -445,6 +467,7 @@ def test_whitespace_only_api_key_raises_error():
Executor(
node_data=node_data,
timeout=timeout,
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -468,6 +491,7 @@ def test_valid_api_key_works():
executor = Executor(
node_data=node_data,
timeout=timeout,
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -515,6 +539,7 @@ def test_executor_with_json_body_and_unquoted_uuid_variable():
executor = Executor(
node_data=node_data,
timeout=HttpRequestNodeTimeout(connect=10, read=30, write=30),
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -559,6 +584,7 @@ def test_executor_with_json_body_and_unquoted_uuid_with_newlines():
executor = Executor(
node_data=node_data,
timeout=HttpRequestNodeTimeout(connect=10, read=30, write=30),
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)
@@ -597,6 +623,7 @@ def test_executor_with_json_body_preserves_numbers_and_strings():
executor = Executor(
node_data=node_data,
timeout=HttpRequestNodeTimeout(connect=10, read=30, write=30),
http_request_config=HTTP_REQUEST_CONFIG,
variable_pool=variable_pool,
)

View File

@@ -1005,7 +1005,7 @@ class TestWorkflowService:
mock_node_class = MagicMock()
mock_node_class.get_default_config.return_value = {"type": "llm", "config": {}}
mock_mapping.values.return_value = [{"latest": mock_node_class}]
mock_mapping.items.return_value = [(NodeType.LLM, {"latest": mock_node_class})]
with patch("services.workflow_service.LATEST_VERSION", "latest"):
result = workflow_service.get_default_block_configs()