Update to version 3.8.0
This commit is contained in:
246
.clang-format
Normal file
246
.clang-format
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
# Clang format version: 18.1.3
|
||||||
|
---
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: BlockIndent
|
||||||
|
AlignArrayOfStructures: None
|
||||||
|
AlignConsecutiveAssignments:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: true
|
||||||
|
AlignConsecutiveBitFields:
|
||||||
|
Enabled: true
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveDeclarations:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveMacros:
|
||||||
|
Enabled: true
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveShortCaseStatements:
|
||||||
|
Enabled: true
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCaseColons: false
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: Align
|
||||||
|
AlignTrailingComments:
|
||||||
|
Kind: Always
|
||||||
|
OverEmptyLines: 0
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowBreakBeforeNoexceptSpecifier: Never
|
||||||
|
AllowShortBlocksOnASingleLine: Empty
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortCompoundRequirementOnASingleLine: true
|
||||||
|
AllowShortEnumsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLambdasOnASingleLine: Empty
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: MultiLine
|
||||||
|
AttributeMacros:
|
||||||
|
- __capability
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: true
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
BeforeLambdaBody: false
|
||||||
|
BeforeWhile: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakAdjacentStringLiterals: true
|
||||||
|
BreakAfterAttributes: Always
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakArrays: false
|
||||||
|
BreakBeforeBinaryOperators: NonAssignment
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BreakBeforeConceptDeclarations: Always
|
||||||
|
BreakBeforeInlineASMColon: OnlyMultiline
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 160
|
||||||
|
CommentPragmas: ""
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerIndentWidth: 2
|
||||||
|
ContinuationIndentWidth: 2
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
EmptyLineAfterAccessModifier: Never
|
||||||
|
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IfMacros:
|
||||||
|
- KJ_IF_MAYBE
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: ^"(llvm|llvm-c|clang|clang-c)/
|
||||||
|
Priority: 2
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: ^(<|"(gtest|gmock|isl|json)/)
|
||||||
|
Priority: 3
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: .*
|
||||||
|
Priority: 1
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
IncludeIsMainRegex: ""
|
||||||
|
IncludeIsMainSourceRegex: ""
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
IndentCaseBlocks: false
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentExternBlock: NoIndent
|
||||||
|
IndentGotoLabels: false
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentRequiresClause: false
|
||||||
|
IndentWidth: 2
|
||||||
|
IndentWrappedFunctionNames: true
|
||||||
|
InsertBraces: true
|
||||||
|
InsertNewlineAtEOF: true
|
||||||
|
InsertTrailingCommas: None
|
||||||
|
IntegerLiteralSeparator:
|
||||||
|
Binary: 0
|
||||||
|
BinaryMinDigits: 0
|
||||||
|
Decimal: 0
|
||||||
|
DecimalMinDigits: 0
|
||||||
|
Hex: 0
|
||||||
|
HexMinDigits: 0
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtEOF: false
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
LambdaBodyIndentation: Signature
|
||||||
|
Language: Cpp
|
||||||
|
LineEnding: LF
|
||||||
|
MacroBlockBegin: ""
|
||||||
|
MacroBlockEnd: ""
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCBreakBeforeNestedBlockParam: true
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PPIndentWidth: -1
|
||||||
|
PackConstructorInitializers: BinPack
|
||||||
|
PenaltyBreakAssignment: 2
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakOpenParenthesis: 0
|
||||||
|
PenaltyBreakScopeResolution: 500
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyIndentedWhitespace: 0
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
PointerAlignment: Right
|
||||||
|
QualifierAlignment: Leave
|
||||||
|
ReferenceAlignment: Pointer
|
||||||
|
ReflowComments: false
|
||||||
|
RemoveBracesLLVM: false
|
||||||
|
RemoveParentheses: Leave
|
||||||
|
RemoveSemicolon: false
|
||||||
|
RequiresClausePosition: OwnLine
|
||||||
|
RequiresExpressionIndentation: OuterScope
|
||||||
|
SeparateDefinitionBlocks: Leave
|
||||||
|
ShortNamespaceLines: 1
|
||||||
|
SkipMacroDefinitionBody: false
|
||||||
|
SortIncludes: Never
|
||||||
|
SortJavaStaticImport: Before
|
||||||
|
SortUsingDeclarations: LexicographicNumeric
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceAroundPointerQualifiers: Default
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCaseColon: false
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeJsonColon: false
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeParensOptions:
|
||||||
|
AfterControlStatements: true
|
||||||
|
AfterForeachMacros: true
|
||||||
|
AfterFunctionDeclarationName: false
|
||||||
|
AfterFunctionDefinitionName: false
|
||||||
|
AfterIfMacros: true
|
||||||
|
AfterOverloadedOperator: true
|
||||||
|
AfterPlacementOperator: true
|
||||||
|
AfterRequiresInClause: false
|
||||||
|
AfterRequiresInExpression: false
|
||||||
|
BeforeNonEmptyParentheses: false
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpacesBeforeTrailingComments: 2
|
||||||
|
SpacesInAngles: Never
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInLineCommentPrefix:
|
||||||
|
Minimum: 1
|
||||||
|
Maximum: -1
|
||||||
|
SpacesInParens: Never
|
||||||
|
SpacesInParensOptions:
|
||||||
|
InConditionalStatements: false
|
||||||
|
InCStyleCasts: false
|
||||||
|
InEmptyParentheses: false
|
||||||
|
Other: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Auto
|
||||||
|
StatementAttributeLikeMacros:
|
||||||
|
- Q_EMIT
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
TabWidth: 2
|
||||||
|
UseTab: Never
|
||||||
|
VerilogBreakBetweenInstancePorts: true
|
||||||
|
WhitespaceSensitiveMacros:
|
||||||
|
- BOOST_PP_STRINGIZE
|
||||||
|
- CF_SWIFT_NAME
|
||||||
|
- NS_SWIFT_NAME
|
||||||
|
- PP_STRINGIZE
|
||||||
|
- STRINGIZE
|
||||||
|
BracedInitializerIndentWidth: 2
|
8
.codespellrc
Normal file
8
.codespellrc
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[codespell]
|
||||||
|
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/spell-check/.codespellrc
|
||||||
|
# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here:
|
||||||
|
ignore-words-list = ba,licence,varius
|
||||||
|
skip = ./.git,./.licenses,__pycache__,.clang-format,.codespellrc,.editorconfig,.flake8,.prettierignore,.yamllint.yml,.gitignore
|
||||||
|
builtin = clear,informal,en-GB_to_en-US
|
||||||
|
check-filenames =
|
||||||
|
check-hidden =
|
60
.editorconfig
Normal file
60
.editorconfig
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/general/.editorconfig
|
||||||
|
# See: https://editorconfig.org/
|
||||||
|
# The formatting style defined in this file is the official standardized style to be used in all Arduino Tooling
|
||||||
|
# projects and should not be modified.
|
||||||
|
# Note: indent style for each file type is defined even when it matches the universal config in order to make it clear
|
||||||
|
# that this type has an official style.
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.{adoc,asc,asciidoc}]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[*.{bash,sh}]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[*.{c,cc,cp,cpp,cxx,h,hh,hpp,hxx,ii,inl,ino,ixx,pde,tpl,tpp,txx}]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[*.{go,mod}]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[*.java]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[*.{js,jsx,json,jsonc,json5,ts,tsx}]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[*.{md,mdx,mkdn,mdown,markdown}]
|
||||||
|
indent_size = unset
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[*.proto]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[*.py]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[*.svg]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[*.{yaml,yml}]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[{.gitconfig,.gitmodules}]
|
||||||
|
indent_style = tab
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
.lh
|
||||||
|
/.pio
|
||||||
|
/.vscode
|
||||||
|
/logs
|
2
.gitpod.Dockerfile
vendored
Normal file
2
.gitpod.Dockerfile
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
FROM gitpod/workspace-python-3.11
|
||||||
|
USER gitpod
|
9
.gitpod.yml
Normal file
9
.gitpod.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
tasks:
|
||||||
|
- command: pip install --upgrade pip && pip install -U platformio && platformio run
|
||||||
|
|
||||||
|
image:
|
||||||
|
file: .gitpod.Dockerfile
|
||||||
|
|
||||||
|
vscode:
|
||||||
|
extensions:
|
||||||
|
- shardulm94.trailing-spaces
|
42
.pre-commit-config.yaml
Normal file
42
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
exclude: |
|
||||||
|
(?x)(
|
||||||
|
^\.github\/|
|
||||||
|
LICENSE$
|
||||||
|
)
|
||||||
|
|
||||||
|
default_language_version:
|
||||||
|
# force all unspecified python hooks to run python3
|
||||||
|
python: python3
|
||||||
|
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: "v5.0.0"
|
||||||
|
hooks:
|
||||||
|
# Generic checks
|
||||||
|
- id: check-case-conflict
|
||||||
|
- id: check-symlinks
|
||||||
|
- id: debug-statements
|
||||||
|
- id: destroyed-symlinks
|
||||||
|
- id: detect-private-key
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
exclude: ^.*\.(bin|BIN)$
|
||||||
|
- id: mixed-line-ending
|
||||||
|
args: [--fix=lf]
|
||||||
|
- id: trailing-whitespace
|
||||||
|
args: [--markdown-linebreak-ext=md]
|
||||||
|
exclude: ^platformio\.ini$
|
||||||
|
|
||||||
|
- repo: https://github.com/codespell-project/codespell
|
||||||
|
rev: "v2.3.0"
|
||||||
|
hooks:
|
||||||
|
# Spell checking
|
||||||
|
- id: codespell
|
||||||
|
exclude: ^.*\.(svd|SVD)$
|
||||||
|
|
||||||
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
|
rev: "v18.1.3"
|
||||||
|
hooks:
|
||||||
|
# C/C++ formatting
|
||||||
|
- id: clang-format
|
||||||
|
types_or: [c, c++]
|
||||||
|
exclude: ^.*\/build_opt\.h$
|
13
README.md
13
README.md
@@ -72,6 +72,19 @@ lib_deps =
|
|||||||
ESP32Async/ESPAsyncWebServer
|
ESP32Async/ESPAsyncWebServer
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### LibreTiny (BK7231N/T, RTL8710B, etc.)
|
||||||
|
|
||||||
|
Version 1.9.1 or newer is required.
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[env:stable]
|
||||||
|
platform = libretiny @ ^1.9.1
|
||||||
|
lib_ldf_mode = chain
|
||||||
|
lib_deps =
|
||||||
|
ESP32Async/AsyncTCP
|
||||||
|
ESP32Async/ESPAsyncWebServer
|
||||||
|
```
|
||||||
|
|
||||||
### Unofficial dependencies
|
### Unofficial dependencies
|
||||||
|
|
||||||
**AsyncTCPSock**
|
**AsyncTCPSock**
|
||||||
|
@@ -1,48 +0,0 @@
|
|||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
|
||||||
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
|
||||||
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
|
||||||
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
|
||||||
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
|
||||||
dapibus elit, id varius sem dui id lacus.</p>
|
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
|
||||||
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
|
||||||
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
|
||||||
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
|
||||||
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
|
||||||
dapibus elit, id varius sem dui id lacus.</p>
|
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
|
||||||
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
|
||||||
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
|
||||||
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
|
||||||
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
|
||||||
dapibus elit, id varius sem dui id lacus.</p>
|
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
|
||||||
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
|
||||||
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
|
||||||
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
|
||||||
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
|
||||||
dapibus elit, id varius sem dui id lacus.</p>
|
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
|
||||||
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
|
||||||
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
|
||||||
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
|
||||||
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
|
||||||
dapibus elit, id varius sem dui id lacus.</p>
|
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
|
||||||
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
|
||||||
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
|
||||||
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
|
||||||
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
|
||||||
dapibus elit, id varius sem dui id lacus.</p>
|
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
|
||||||
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
|
||||||
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
|
||||||
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
|
||||||
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
|
||||||
dapibus elit, id varius sem dui id lacus.</p>
|
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
|
||||||
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
|
||||||
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
|
||||||
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
|
||||||
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
|
||||||
dapibus elit, id varius sem dui id lacus.
|
|
@@ -2,7 +2,7 @@
|
|||||||
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
|
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
|
||||||
|
|
||||||
#include <DNSServer.h>
|
#include <DNSServer.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -20,7 +20,7 @@ static AsyncWebServer server(80);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
210
examples/AsyncTunnel/AsyncTunnel.ino
Normal file
210
examples/AsyncTunnel/AsyncTunnel.ino
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
|
||||||
|
|
||||||
|
//
|
||||||
|
// Shows how to trigger an async client request from a browser request and send the client response back to the browser through websocket
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
|
#include <AsyncTCP.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
|
||||||
|
#include <RPAsyncTCP.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
#define WIFI_SSID "IoT"
|
||||||
|
#define WIFI_PASSWORD ""
|
||||||
|
|
||||||
|
static AsyncWebServer server(80);
|
||||||
|
static AsyncWebSocketMessageHandler wsHandler;
|
||||||
|
static AsyncWebSocket ws("/ws", wsHandler.eventHandler());
|
||||||
|
|
||||||
|
static const char *htmlContent PROGMEM = R"(
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>WebSocket Tunnel Example</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>WebSocket Tunnel Example</h1>
|
||||||
|
<div><input type="text" id="url" value="http://www.google.com" /></div>
|
||||||
|
<div><button onclick='fetch()'>Fetch</button></div>
|
||||||
|
<div><pre id="response"></pre></div>
|
||||||
|
<script>
|
||||||
|
var ws = new WebSocket('/ws');
|
||||||
|
ws.binaryType = "arraybuffer";
|
||||||
|
ws.onopen = function() {
|
||||||
|
console.log("WebSocket connected");
|
||||||
|
};
|
||||||
|
ws.onmessage = function(event) {
|
||||||
|
let uint8array = new Uint8Array(event.data);
|
||||||
|
let string = new TextDecoder().decode(uint8array);
|
||||||
|
console.log("WebSocket message: " + string);
|
||||||
|
document.getElementById("response").innerText += string;
|
||||||
|
};
|
||||||
|
ws.onclose = function() {
|
||||||
|
console.log("WebSocket closed");
|
||||||
|
};
|
||||||
|
ws.onerror = function(error) {
|
||||||
|
console.log("WebSocket error: " + error);
|
||||||
|
};
|
||||||
|
function fetch() {
|
||||||
|
document.getElementById("response").innerText = "";
|
||||||
|
var url = document.getElementById("url").value;
|
||||||
|
ws.send(url);
|
||||||
|
console.log("WebSocket sent: " + url);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)";
|
||||||
|
static const size_t htmlContentLength = strlen_P(htmlContent);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
|
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
Serial.println("Connected to WiFi!");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
|
request->send(200, "text/html", (const uint8_t *)htmlContent, htmlContentLength);
|
||||||
|
});
|
||||||
|
|
||||||
|
wsHandler.onMessage([](AsyncWebSocket *server, AsyncWebSocketClient *wsClient, const uint8_t *data, size_t len) {
|
||||||
|
String url;
|
||||||
|
String host;
|
||||||
|
String port;
|
||||||
|
String path;
|
||||||
|
|
||||||
|
url.concat((const char *)data, len);
|
||||||
|
|
||||||
|
if (!url.startsWith("http://")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!url.endsWith("/")) {
|
||||||
|
url += "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the URL to extract the host and port
|
||||||
|
int start = url.indexOf("://") + 3;
|
||||||
|
int end = url.indexOf("/", start);
|
||||||
|
if (end == -1) {
|
||||||
|
end = url.length();
|
||||||
|
}
|
||||||
|
String hostPort = url.substring(start, end);
|
||||||
|
int colonIndex = hostPort.indexOf(":");
|
||||||
|
if (colonIndex != -1) {
|
||||||
|
host = hostPort.substring(0, colonIndex);
|
||||||
|
port = hostPort.substring(colonIndex + 1);
|
||||||
|
} else {
|
||||||
|
host = hostPort;
|
||||||
|
port = "80"; // Default HTTP port
|
||||||
|
}
|
||||||
|
path = url.substring(end);
|
||||||
|
|
||||||
|
Serial.printf("Host: %s\n", host.c_str());
|
||||||
|
Serial.printf("Port: %s\n", port.c_str());
|
||||||
|
Serial.printf("Path: %s\n", path.c_str());
|
||||||
|
|
||||||
|
// Ensure client does not get deleted while the websocket holds a reference to it
|
||||||
|
std::shared_ptr<AsyncClient> *safeAsyncClient = new std::shared_ptr<AsyncClient>(std::make_shared<AsyncClient>());
|
||||||
|
AsyncClient *asyncClient = safeAsyncClient->get();
|
||||||
|
|
||||||
|
asyncClient->onDisconnect([safeAsyncClient](void *arg, AsyncClient *client) {
|
||||||
|
Serial.printf("Tunnel disconnected!\n");
|
||||||
|
delete safeAsyncClient;
|
||||||
|
});
|
||||||
|
|
||||||
|
// register a callback when an error occurs
|
||||||
|
// note: onDisconnect also called on error
|
||||||
|
asyncClient->onError([](void *arg, AsyncClient *client, int8_t error) {
|
||||||
|
Serial.printf("Tunnel error: %s\n", client->errorToString(error));
|
||||||
|
});
|
||||||
|
|
||||||
|
// register a callback when data arrives, to accumulate it
|
||||||
|
asyncClient->onPacket(
|
||||||
|
[safeAsyncClient](void *arg, AsyncClient *, struct pbuf *pb) {
|
||||||
|
std::shared_ptr<AsyncClient> safeAsyncClientRef = *safeAsyncClient; // add a reference
|
||||||
|
AsyncWebSocketClient *wsClient = (AsyncWebSocketClient *)arg;
|
||||||
|
Serial.printf("Tunnel received %u bytes\n", pb->len);
|
||||||
|
AsyncWebSocketSharedBuffer wsBuffer =
|
||||||
|
AsyncWebSocketSharedBuffer(new std::vector<uint8_t>((uint8_t *)pb->payload, (uint8_t *)pb->payload + pb->len), [=](std::vector<uint8_t> *bufptr) {
|
||||||
|
delete bufptr;
|
||||||
|
Serial.printf("ACK %u bytes\n", pb->len);
|
||||||
|
safeAsyncClientRef->ackPacket(pb);
|
||||||
|
});
|
||||||
|
Serial.printf("Tunnel sending %u bytes\n", wsBuffer->size());
|
||||||
|
Serial.printf("%.*s\n", (int)wsBuffer->size(), wsBuffer->data());
|
||||||
|
wsClient->binary(std::move(wsBuffer));
|
||||||
|
},
|
||||||
|
wsClient
|
||||||
|
);
|
||||||
|
|
||||||
|
asyncClient->onConnect([=](void *arg, AsyncClient *client) {
|
||||||
|
Serial.printf("Tunnel connected!\n");
|
||||||
|
|
||||||
|
client->write("GET ");
|
||||||
|
client->write(path.c_str());
|
||||||
|
client->write(" HTTP/1.1\r\n");
|
||||||
|
client->write("Host: ");
|
||||||
|
client->write(host.c_str());
|
||||||
|
client->write(":");
|
||||||
|
client->write(port.c_str());
|
||||||
|
client->write("\r\n");
|
||||||
|
client->write("User-Agent: ESP32\r\n");
|
||||||
|
client->write("Accept: */*\r\n");
|
||||||
|
client->write("Connection: close\r\n");
|
||||||
|
client->write("\r\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
Serial.printf("Fetching: http://%s:%s%s\n", host.c_str(), port.c_str(), path.c_str());
|
||||||
|
|
||||||
|
if (!asyncClient->connect(host.c_str(), port.toInt())) {
|
||||||
|
Serial.printf("Failed to open tunnel!\n");
|
||||||
|
delete safeAsyncClient;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
wsHandler.onConnect([](AsyncWebSocket *server, AsyncWebSocketClient *client) {
|
||||||
|
Serial.printf("Client %" PRIu32 " connected\n", client->id());
|
||||||
|
client->binary("WebSocket connected!");
|
||||||
|
});
|
||||||
|
|
||||||
|
wsHandler.onDisconnect([](AsyncWebSocket *server, uint32_t clientId) {
|
||||||
|
Serial.printf("Client %" PRIu32 " disconnected\n", clientId);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.addHandler(&ws);
|
||||||
|
server.begin();
|
||||||
|
Serial.println("Server started!");
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t lastHeap = 0;
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
ws.cleanupClients(2);
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
uint32_t now = millis();
|
||||||
|
if (now - lastHeap >= 2000) {
|
||||||
|
Serial.printf("Uptime: %3lu s, Free heap: %" PRIu32 "\n", millis() / 1000, ESP.getFreeHeap());
|
||||||
|
lastHeap = now;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
delay(500);
|
||||||
|
}
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -52,7 +52,7 @@ static AsyncAuthorizationMiddleware authz([](AsyncWebServerRequest *request) {
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -25,7 +25,7 @@ static AsyncCorsMiddleware cors;
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
|
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
|
||||||
|
|
||||||
#include <DNSServer.h>
|
#include <DNSServer.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -28,7 +28,7 @@ public:
|
|||||||
response->print("<!DOCTYPE html><html><head><title>Captive Portal</title></head><body>");
|
response->print("<!DOCTYPE html><html><head><title>Captive Portal</title></head><body>");
|
||||||
response->print("<p>This is our captive portal front page.</p>");
|
response->print("<p>This is our captive portal front page.</p>");
|
||||||
response->printf("<p>You were trying to reach: http://%s%s</p>", request->host().c_str(), request->url().c_str());
|
response->printf("<p>You were trying to reach: http://%s%s</p>", request->host().c_str(), request->url().c_str());
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
response->printf("<p>Try opening <a href='http://%s'>this link</a> instead</p>", WiFi.softAPIP().toString().c_str());
|
response->printf("<p>Try opening <a href='http://%s'>this link</a> instead</p>", WiFi.softAPIP().toString().c_str());
|
||||||
#endif
|
#endif
|
||||||
response->print("</body></html>");
|
response->print("</body></html>");
|
||||||
@@ -41,7 +41,7 @@ void setup() {
|
|||||||
Serial.println();
|
Serial.println();
|
||||||
Serial.println("Configuring access point...");
|
Serial.println("Configuring access point...");
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
if (!WiFi.softAP("esp-captive")) {
|
if (!WiFi.softAP("esp-captive")) {
|
||||||
Serial.println("Soft AP creation failed.");
|
Serial.println("Soft AP creation failed.");
|
||||||
while (1);
|
while (1);
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -86,7 +86,7 @@ static const size_t htmlContentLength = strlen_P(htmlContent);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -86,7 +86,7 @@ static const size_t htmlContentLength = strlen_P(htmlContent);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -96,7 +96,7 @@ static int key = -1;
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
@@ -131,9 +131,17 @@ void setup() {
|
|||||||
"/api", HTTP_POST,
|
"/api", HTTP_POST,
|
||||||
[](AsyncWebServerRequest *request) {
|
[](AsyncWebServerRequest *request) {
|
||||||
// request parsing has finished
|
// request parsing has finished
|
||||||
|
String *data = (String *)request->_tempObject;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
request->send(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// no data ?
|
// no data ?
|
||||||
if (!((String *)request->_tempObject)->length()) {
|
if (!data->length()) {
|
||||||
|
delete data;
|
||||||
|
request->_tempObject = nullptr;
|
||||||
request->send(400);
|
request->send(400);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -141,11 +149,16 @@ void setup() {
|
|||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
|
|
||||||
// deserialize and check for errors
|
// deserialize and check for errors
|
||||||
if (deserializeJson(doc, *(String *)request->_tempObject)) {
|
if (deserializeJson(doc, *data)) {
|
||||||
|
delete data;
|
||||||
|
request->_tempObject = nullptr;
|
||||||
request->send(400);
|
request->send(400);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete data;
|
||||||
|
request->_tempObject = nullptr;
|
||||||
|
|
||||||
// start UART com: UART will send the data to the Serial console and wait for the key press
|
// start UART com: UART will send the data to the Serial console and wait for the key press
|
||||||
triggerUART = doc["input"].as<const char *>();
|
triggerUART = doc["input"].as<const char *>();
|
||||||
key = -1;
|
key = -1;
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -24,7 +24,7 @@ static AsyncWebServer server(80);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <DNSServer.h>
|
#include <DNSServer.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -32,7 +32,7 @@ public:
|
|||||||
response->print("<!DOCTYPE html><html><head><title>Captive Portal</title></head><body>");
|
response->print("<!DOCTYPE html><html><head><title>Captive Portal</title></head><body>");
|
||||||
response->print("<p>This is out captive portal front page.</p>");
|
response->print("<p>This is out captive portal front page.</p>");
|
||||||
response->printf("<p>You were trying to reach: http://%s%s</p>", request->host().c_str(), request->url().c_str());
|
response->printf("<p>You were trying to reach: http://%s%s</p>", request->host().c_str(), request->url().c_str());
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
response->printf("<p>Try opening <a href='http://%s'>this link</a> instead</p>", WiFi.softAPIP().toString().c_str());
|
response->printf("<p>Try opening <a href='http://%s'>this link</a> instead</p>", WiFi.softAPIP().toString().c_str());
|
||||||
#endif
|
#endif
|
||||||
response->print("</body></html>");
|
response->print("</body></html>");
|
||||||
@@ -51,17 +51,17 @@ void setup() {
|
|||||||
"/", HTTP_GET,
|
"/", HTTP_GET,
|
||||||
[](AsyncWebServerRequest *request) {
|
[](AsyncWebServerRequest *request) {
|
||||||
Serial.println("Captive portal request...");
|
Serial.println("Captive portal request...");
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
Serial.println("WiFi.localIP(): " + WiFi.localIP().toString());
|
Serial.println("WiFi.localIP(): " + WiFi.localIP().toString());
|
||||||
#endif
|
#endif
|
||||||
Serial.println("request->client()->localIP(): " + request->client()->localIP().toString());
|
Serial.println("request->client()->localIP(): " + request->client()->localIP().toString());
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
Serial.println("WiFi.type(): " + String((int)WiFi.localIP().type()));
|
Serial.println("WiFi.type(): " + String((int)WiFi.localIP().type()));
|
||||||
#endif
|
#endif
|
||||||
Serial.println("request->client()->type(): " + String((int)request->client()->localIP().type()));
|
Serial.println("request->client()->type(): " + String((int)request->client()->localIP().type()));
|
||||||
#endif
|
#endif
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
Serial.println(WiFi.localIP() == request->client()->localIP() ? "should be: ON_STA_FILTER" : "should be: ON_AP_FILTER");
|
Serial.println(WiFi.localIP() == request->client()->localIP() ? "should be: ON_STA_FILTER" : "should be: ON_AP_FILTER");
|
||||||
Serial.println(WiFi.localIP() == request->client()->localIP());
|
Serial.println(WiFi.localIP() == request->client()->localIP());
|
||||||
Serial.println(WiFi.localIP().toString() == request->client()->localIP().toString());
|
Serial.println(WiFi.localIP().toString() == request->client()->localIP().toString());
|
||||||
@@ -77,17 +77,17 @@ void setup() {
|
|||||||
"/", HTTP_GET,
|
"/", HTTP_GET,
|
||||||
[](AsyncWebServerRequest *request) {
|
[](AsyncWebServerRequest *request) {
|
||||||
Serial.println("Website request...");
|
Serial.println("Website request...");
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
Serial.println("WiFi.localIP(): " + WiFi.localIP().toString());
|
Serial.println("WiFi.localIP(): " + WiFi.localIP().toString());
|
||||||
#endif
|
#endif
|
||||||
Serial.println("request->client()->localIP(): " + request->client()->localIP().toString());
|
Serial.println("request->client()->localIP(): " + request->client()->localIP().toString());
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
Serial.println("WiFi.type(): " + String((int)WiFi.localIP().type()));
|
Serial.println("WiFi.type(): " + String((int)WiFi.localIP().type()));
|
||||||
#endif
|
#endif
|
||||||
Serial.println("request->client()->type(): " + String((int)request->client()->localIP().type()));
|
Serial.println("request->client()->type(): " + String((int)request->client()->localIP().type()));
|
||||||
#endif
|
#endif
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
Serial.println(WiFi.localIP() == request->client()->localIP() ? "should be: ON_STA_FILTER" : "should be: ON_AP_FILTER");
|
Serial.println(WiFi.localIP() == request->client()->localIP() ? "should be: ON_STA_FILTER" : "should be: ON_AP_FILTER");
|
||||||
Serial.println(WiFi.localIP() == request->client()->localIP());
|
Serial.println(WiFi.localIP() == request->client()->localIP());
|
||||||
Serial.println(WiFi.localIP().toString() == request->client()->localIP().toString());
|
Serial.println(WiFi.localIP().toString() == request->client()->localIP().toString());
|
||||||
@@ -113,7 +113,7 @@ void setup() {
|
|||||||
// dnsServer.stop();
|
// dnsServer.stop();
|
||||||
// WiFi.softAPdisconnect();
|
// WiFi.softAPdisconnect();
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.persistent(false);
|
WiFi.persistent(false);
|
||||||
WiFi.begin("IoT");
|
WiFi.begin("IoT");
|
||||||
while (WiFi.status() != WL_CONNECTED) {
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -86,7 +86,7 @@ static const size_t htmlContentLength = strlen_P(htmlContent);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -33,7 +33,7 @@ AsyncHeaderFreeMiddleware headerFree;
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
@@ -79,6 +79,29 @@ void setup() {
|
|||||||
)
|
)
|
||||||
.addMiddleware(&headerFree);
|
.addMiddleware(&headerFree);
|
||||||
|
|
||||||
|
// curl -v http://192.168.4.1/
|
||||||
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
|
AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Hello, world!");
|
||||||
|
response->addHeader(AsyncWebHeader::parse("X-Test-1: value1"));
|
||||||
|
response->addHeader(AsyncWebHeader::parse("X-Test-2:value2"));
|
||||||
|
response->addHeader(AsyncWebHeader::parse("X-Test-3:"));
|
||||||
|
response->addHeader(AsyncWebHeader::parse("X-Test-4: "));
|
||||||
|
response->addHeader(AsyncWebHeader::parse(""));
|
||||||
|
response->addHeader(AsyncWebHeader::parse(":"));
|
||||||
|
request->send(response);
|
||||||
|
/**
|
||||||
|
< HTTP/1.1 200 OK
|
||||||
|
< connection: close
|
||||||
|
< X-Test-1: value1
|
||||||
|
< X-Test-2: value2
|
||||||
|
< X-Test-3:
|
||||||
|
< X-Test-4:
|
||||||
|
< accept-ranges: none
|
||||||
|
< content-length: 13
|
||||||
|
< content-type: text/plain
|
||||||
|
*/
|
||||||
|
});
|
||||||
|
|
||||||
server.begin();
|
server.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -24,7 +24,7 @@ static AsyncWebServer server(80);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -34,7 +34,7 @@ static AsyncCallbackJsonWebHandler *handler = new AsyncCallbackJsonWebHandler("/
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
@@ -63,14 +63,27 @@ void setup() {
|
|||||||
JsonObject root = doc.to<JsonObject>();
|
JsonObject root = doc.to<JsonObject>();
|
||||||
root["foo"] = "bar";
|
root["foo"] = "bar";
|
||||||
serializeJson(root, *response);
|
serializeJson(root, *response);
|
||||||
|
Serial.println();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
// curl -v -X POST -H 'Content-Type: application/json' -d '{"name":"You"}' http://192.168.4.1/json2
|
// curl -v -X POST -H 'Content-Type: application/json' -d '{"name":"You"}' http://192.168.4.1/json2
|
||||||
// curl -v -X PUT -H 'Content-Type: application/json' -d '{"name":"You"}' http://192.168.4.1/json2
|
// curl -v -X PUT -H 'Content-Type: application/json' -d '{"name":"You"}' http://192.168.4.1/json2
|
||||||
|
//
|
||||||
|
// edge cases:
|
||||||
|
//
|
||||||
|
// curl -v -X POST -H "Content-Type: application/json" -d "1234" -H "Content-Length: 5" http://192.168.4.1/json2 => rx timeout
|
||||||
|
// curl -v -X POST -H "Content-Type: application/json" -d "1234" -H "Content-Length: 2" http://192.168.4.1/json2 => 12
|
||||||
|
// curl -v -X POST -H "Content-Type: application/json" -d "1234" -H "Content-Length: 4" http://192.168.4.1/json2 => 1234
|
||||||
|
// curl -v -X POST -H "Content-Type: application/json" -d "1234" -H "Content-Length: 10" http://192.168.4.1/json2 => rx timeout
|
||||||
|
// curl -v -X POST -H "Content-Type: application/json" -d "12345678" -H "Content-Length: 8" http://192.168.4.1/json2 => 12345678
|
||||||
|
// curl -v -X POST -H "Content-Type: application/json" -d "123456789" -H "Content-Length: 8" http://192.168.4.1/json2 => 12345678
|
||||||
|
// curl -v -X POST -H "Content-Type: application/json" -d "123456789" -H "Content-Length: 9" http://192.168.4.1/json2 => 413: Content length exceeds maximum allowed
|
||||||
|
handler->setMaxContentLength(8);
|
||||||
handler->setMethod(HTTP_POST | HTTP_PUT);
|
handler->setMethod(HTTP_POST | HTTP_PUT);
|
||||||
handler->onRequest([](AsyncWebServerRequest *request, JsonVariant &json) {
|
handler->onRequest([](AsyncWebServerRequest *request, JsonVariant &json) {
|
||||||
serializeJson(json, Serial);
|
serializeJson(json, Serial);
|
||||||
|
Serial.println();
|
||||||
AsyncJsonResponse *response = new AsyncJsonResponse();
|
AsyncJsonResponse *response = new AsyncJsonResponse();
|
||||||
JsonObject root = response->getRoot().to<JsonObject>();
|
JsonObject root = response->getRoot().to<JsonObject>();
|
||||||
root["hello"] = json.as<JsonObject>()["name"];
|
root["hello"] = json.as<JsonObject>()["name"];
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -25,7 +25,7 @@ static AsyncLoggingMiddleware requestLogger;
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -34,7 +34,7 @@ static AsyncCallbackMessagePackWebHandler *handler = new AsyncCallbackMessagePac
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -34,7 +34,7 @@ public:
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -74,7 +74,7 @@ static const size_t htmlContentLength = strlen_P(htmlContent);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -34,7 +34,7 @@ static AsyncWebServer server(80);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -91,7 +91,7 @@ static volatile size_t requests = 0;
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -25,7 +25,7 @@ static AsyncRateLimitMiddleware rateLimit;
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -24,7 +24,7 @@ static AsyncWebServer server(80);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -34,7 +34,7 @@ static AsyncWebServerRequestPtr gpioRequest;
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -94,7 +94,7 @@ static bool processLongRunningOperation(LongRunningOperation *op) {
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -24,7 +24,7 @@ static AsyncWebServer server(80);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -24,7 +24,7 @@ static AsyncWebServer server(80);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -58,7 +58,7 @@ static AsyncEventSource events("/events");
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
141
examples/ServerSentEvents_PR156/ServerSentEvents_PR156.ino
Normal file
141
examples/ServerSentEvents_PR156/ServerSentEvents_PR156.ino
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
|
||||||
|
|
||||||
|
//
|
||||||
|
// SSE example
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
|
#include <AsyncTCP.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
|
||||||
|
#include <RPAsyncTCP.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
static const char *htmlContent PROGMEM = R"(
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Server-Sent Events</title>
|
||||||
|
<script>
|
||||||
|
if (!!window.EventSource) {
|
||||||
|
var source = new EventSource('/events');
|
||||||
|
source.onopen = function(e) {
|
||||||
|
console.log("Events Connected");
|
||||||
|
};
|
||||||
|
source.onerror = function(e) {
|
||||||
|
if (e.target.readyState != EventSource.OPEN) {
|
||||||
|
console.log("Events Disconnected");
|
||||||
|
}
|
||||||
|
// Uncomment below to prevent the client from proactively establishing a new connection.
|
||||||
|
// source.close();
|
||||||
|
};
|
||||||
|
source.onmessage = function(e) {
|
||||||
|
console.log("Message: " + e.data);
|
||||||
|
};
|
||||||
|
source.addEventListener('heartbeat', function(e) {
|
||||||
|
console.log("Heartbeat", e.data);
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Open your browser console!</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)";
|
||||||
|
|
||||||
|
static const size_t htmlContentLength = strlen_P(htmlContent);
|
||||||
|
|
||||||
|
static AsyncWebServer server(80);
|
||||||
|
static AsyncEventSource events("/events");
|
||||||
|
|
||||||
|
static volatile size_t connectionCount = 0;
|
||||||
|
static volatile uint32_t timestampConnected = 0;
|
||||||
|
static constexpr uint32_t timeoutClose = 15000;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
|
WiFi.mode(WIFI_AP);
|
||||||
|
WiFi.softAP("esp-captive");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// curl -v http://192.168.4.1/
|
||||||
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
|
// need to cast to uint8_t*
|
||||||
|
// if you do not, the const char* will be copied in a temporary String buffer
|
||||||
|
request->send(200, "text/html", (uint8_t *)htmlContent, htmlContentLength);
|
||||||
|
});
|
||||||
|
|
||||||
|
events.onConnect([](AsyncEventSourceClient *client) {
|
||||||
|
/**
|
||||||
|
* @brief: Purpose for a test case: count() function
|
||||||
|
* Task watchdog shall be triggered due to a self-deadlock by mutex handling of the AsyncEventSource.
|
||||||
|
*
|
||||||
|
* E (61642) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
|
||||||
|
* E (61642) task_wdt: - async_tcp (CPU 0/1)
|
||||||
|
*
|
||||||
|
* Resolve: using recursive_mutex insteads of mutex.
|
||||||
|
*/
|
||||||
|
connectionCount = events.count();
|
||||||
|
|
||||||
|
timestampConnected = millis();
|
||||||
|
Serial.printf("SSE Client connected! ID: %" PRIu32 "\n", client->lastId());
|
||||||
|
client->send("hello!", NULL, millis(), 1000);
|
||||||
|
Serial.printf("Number of connected clients: %u\n", connectionCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
events.onDisconnect([](AsyncEventSourceClient *client) {
|
||||||
|
connectionCount = events.count();
|
||||||
|
Serial.printf("SSE Client disconnected! ID: %" PRIu32 "\n", client->lastId());
|
||||||
|
Serial.printf("Number of connected clients: %u\n", connectionCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.addHandler(&events);
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t deltaSSE = 3000;
|
||||||
|
static uint32_t lastSSE = 0;
|
||||||
|
static uint32_t lastHeap = 0;
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
uint32_t now = millis();
|
||||||
|
if (connectionCount > 0) {
|
||||||
|
if (now - lastSSE >= deltaSSE) {
|
||||||
|
events.send(String("ping-") + now, "heartbeat", now);
|
||||||
|
lastSSE = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief: Purpose for a test case: close() function
|
||||||
|
* Task watchdog shall be triggered due to a self-deadlock by mutex handling of the AsyncEventSource.
|
||||||
|
*
|
||||||
|
* E (61642) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
|
||||||
|
* E (61642) task_wdt: - async_tcp (CPU 0/1)
|
||||||
|
*
|
||||||
|
* Resolve: using recursive_mutex insteads of mutex.
|
||||||
|
*/
|
||||||
|
if (now - timestampConnected >= timeoutClose) {
|
||||||
|
Serial.printf("SSE Clients close\n");
|
||||||
|
events.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
if (now - lastHeap >= 2000) {
|
||||||
|
Serial.printf("Free heap: %" PRIu32 "\n", ESP.getFreeHeap());
|
||||||
|
lastHeap = now;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -25,7 +25,7 @@ static AsyncWebServer server2(80);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -27,7 +27,7 @@ static AsyncLoggingMiddleware logging;
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -89,7 +89,7 @@ static size_t charactersIndex = 0;
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -84,10 +84,34 @@ static const char *htmlContent PROGMEM = R"(
|
|||||||
|
|
||||||
static const size_t htmlContentLength = strlen_P(htmlContent);
|
static const size_t htmlContentLength = strlen_P(htmlContent);
|
||||||
|
|
||||||
|
// sample_html_gz.h
|
||||||
|
static const uint8_t index2_html_gz[] = {
|
||||||
|
0x1f, 0x8b, 0x08, 0x08, 0x13, 0x45, 0x92, 0x68, 0x00, 0x03, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x32, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x00, 0xed, 0x98, 0xcb,
|
||||||
|
0x6e, 0xdc, 0x30, 0x0c, 0x45, 0xf7, 0xf3, 0x15, 0xcc, 0xde, 0xb0, 0x91, 0xbd, 0xe1, 0x4d, 0x1f, 0x48, 0x81, 0xbc, 0x8a, 0x26, 0x2d, 0xba, 0xe4, 0x48,
|
||||||
|
0x8c, 0x87, 0x81, 0x1e, 0x0e, 0x25, 0x19, 0xc8, 0xdf, 0x97, 0xb2, 0x67, 0x82, 0x6c, 0xfa, 0x07, 0x32, 0x0c, 0x58, 0xa6, 0xa8, 0xcb, 0x4b, 0xe9, 0xac,
|
||||||
|
0x34, 0x5e, 0x7d, 0x7d, 0xf8, 0xf2, 0xf4, 0xf7, 0xf1, 0x1b, 0x9c, 0xb2, 0x77, 0xd3, 0x61, 0xbc, 0x7c, 0x08, 0xed, 0x74, 0x00, 0x7d, 0xc6, 0xcc, 0xd9,
|
||||||
|
0xd1, 0xf4, 0x0b, 0xfd, 0xe2, 0x08, 0x6e, 0x9e, 0xee, 0x6e, 0xc7, 0x61, 0x0f, 0x1d, 0xc6, 0x61, 0x4f, 0x1b, 0x8f, 0xd1, 0xbe, 0x9f, 0xb3, 0x4f, 0xd7,
|
||||||
|
0xd3, 0x0d, 0x39, 0x17, 0x3b, 0xf8, 0x13, 0xc5, 0xd9, 0x2b, 0xcd, 0xb9, 0x3e, 0x4f, 0x2d, 0xd3, 0x6d, 0x14, 0xf2, 0xc0, 0x4b, 0x2a, 0x1e, 0x6c, 0x74,
|
||||||
|
0x51, 0x20, 0x71, 0x06, 0xf4, 0x94, 0x3b, 0x30, 0x31, 0x24, 0x32, 0x99, 0x72, 0x11, 0x40, 0xcb, 0x0b, 0x27, 0xc3, 0x61, 0x06, 0x72, 0x9c, 0x7b, 0x78,
|
||||||
|
0x94, 0xc8, 0x01, 0xa8, 0x70, 0xf2, 0xd1, 0x76, 0xb0, 0x14, 0x29, 0x09, 0xf0, 0x12, 0xd8, 0xe4, 0xe5, 0x14, 0x83, 0x29, 0xa9, 0x83, 0x22, 0x01, 0xcf,
|
||||||
|
0x35, 0x4c, 0x91, 0xa4, 0x89, 0x1e, 0x53, 0xc2, 0x4e, 0xb3, 0xc1, 0xb2, 0xc9, 0x1a, 0xcf, 0xea, 0x50, 0xe3, 0xaf, 0x25, 0xe5, 0x08, 0x68, 0xf6, 0x41,
|
||||||
|
0x0f, 0x3f, 0x55, 0xee, 0xad, 0x10, 0x14, 0xe7, 0xd0, 0x9b, 0x28, 0x0b, 0xc9, 0x26, 0x8d, 0x62, 0x0a, 0x04, 0x32, 0x90, 0xa3, 0xe8, 0xfb, 0x79, 0xbe,
|
||||||
|
0x83, 0x95, 0x1c, 0xbc, 0x90, 0x78, 0x0a, 0x55, 0x79, 0x97, 0xfc, 0xf8, 0xef, 0xe1, 0x37, 0xaf, 0xe8, 0xb5, 0x56, 0x22, 0x5b, 0x53, 0xb5, 0xdd, 0x92,
|
||||||
|
0xb7, 0xa6, 0x76, 0x65, 0x63, 0x8a, 0x4f, 0x18, 0x6a, 0xf7, 0x73, 0xad, 0xbc, 0x4f, 0x07, 0xd6, 0x95, 0xcf, 0xb9, 0x3a, 0xde, 0x05, 0x75, 0xe0, 0x50,
|
||||||
|
0xbb, 0x83, 0x15, 0x85, 0xf5, 0x33, 0x0b, 0xae, 0x6c, 0xb1, 0x26, 0xe3, 0xb9, 0x9b, 0x1e, 0xee, 0xab, 0x2f, 0x78, 0x41, 0xc3, 0x8e, 0x13, 0xf7, 0x5b,
|
||||||
|
0x81, 0x1f, 0x21, 0xd3, 0x4c, 0xba, 0xa3, 0xc5, 0x54, 0xe7, 0x9f, 0x37, 0xb9, 0xb8, 0x2c, 0x6c, 0x98, 0x74, 0xe5, 0xf7, 0x92, 0x0c, 0xa9, 0xeb, 0x32,
|
||||||
|
0x33, 0xea, 0x51, 0x78, 0xfe, 0x38, 0x17, 0x38, 0xf2, 0x91, 0x82, 0xd5, 0xce, 0x56, 0x5e, 0x49, 0x44, 0xb7, 0x31, 0x8a, 0x61, 0x70, 0x14, 0x37, 0x7d,
|
||||||
|
0x8b, 0x0b, 0x1f, 0xd5, 0x50, 0xed, 0xa8, 0x03, 0xb6, 0x17, 0x83, 0x49, 0xcf, 0xd9, 0x16, 0xae, 0x91, 0xcd, 0x78, 0x3f, 0x0e, 0x4b, 0xc3, 0xa0, 0x61,
|
||||||
|
0xd0, 0x30, 0x68, 0x18, 0x34, 0x0c, 0x1a, 0x06, 0x0d, 0x83, 0x86, 0x41, 0xc3, 0xa0, 0x61, 0xd0, 0x30, 0x68, 0x18, 0x34, 0x0c, 0x1a, 0x06, 0xff, 0xc1,
|
||||||
|
0x60, 0x1c, 0xf6, 0xab, 0x85, 0x71, 0xd8, 0xee, 0x25, 0xfe, 0x01, 0xa0, 0xec, 0x78, 0xfe, 0xae, 0x10, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
static const size_t index2_html_gz_len = sizeof(index2_html_gz);
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
@@ -105,6 +129,13 @@ void setup() {
|
|||||||
f.close();
|
f.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
File f = LittleFS.open("/index2.html.gz", "w");
|
||||||
|
assert(f);
|
||||||
|
f.write(index2_html_gz, index2_html_gz_len);
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
|
||||||
LittleFS.mkdir("/files");
|
LittleFS.mkdir("/files");
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -129,6 +160,9 @@ void setup() {
|
|||||||
// curl -v http://192.168.4.1/index.html
|
// curl -v http://192.168.4.1/index.html
|
||||||
server.serveStatic("/index.html", LittleFS, "/index.html");
|
server.serveStatic("/index.html", LittleFS, "/index.html");
|
||||||
|
|
||||||
|
// curl -v http://192.168.4.1/index2.html | gunzip -c
|
||||||
|
server.serveStatic("/index2.html", LittleFS, "/index2.html");
|
||||||
|
|
||||||
// Example to serve a directory content
|
// Example to serve a directory content
|
||||||
// curl -v http://192.168.4.1/base/ => serves a.txt
|
// curl -v http://192.168.4.1/base/ => serves a.txt
|
||||||
// curl -v http://192.168.4.1/base/a.txt => serves a.txt
|
// curl -v http://192.168.4.1/base/a.txt => serves a.txt
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -36,7 +36,7 @@ static const size_t htmlContentLength = strlen_P(htmlContent);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -31,7 +31,7 @@ void setup() {
|
|||||||
LittleFS.begin();
|
LittleFS.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -25,7 +25,7 @@ static AsyncWebSocket ws("/ws");
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
@@ -102,8 +102,10 @@ void loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (now - lastHeap >= 2000) {
|
if (now - lastHeap >= 2000) {
|
||||||
// cleanup disconnected clients or too many clients
|
Serial.printf("Connected clients: %u / %u total\n", ws.count(), ws.getClients().size());
|
||||||
ws.cleanupClients();
|
|
||||||
|
// this can be called to also set a soft limit on the number of connected clients
|
||||||
|
ws.cleanupClients(2); // no more than 2 clients
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
Serial.printf("Free heap: %" PRIu32 "\n", ESP.getFreeHeap());
|
Serial.printf("Free heap: %" PRIu32 "\n", ESP.getFreeHeap());
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
@@ -71,7 +71,7 @@ static const size_t htmlContentLength = strlen_P(htmlContent);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -25,11 +25,14 @@ files:
|
|||||||
- "platformio.ini"
|
- "platformio.ini"
|
||||||
- "pre-commit.requirements.txt"
|
- "pre-commit.requirements.txt"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
espressif/arduino-esp32:
|
||||||
|
version: "^3.1.1"
|
||||||
|
require: public
|
||||||
esp32async/asynctcp:
|
esp32async/asynctcp:
|
||||||
version: "^3.3.8"
|
version: "^3.4.7"
|
||||||
require: public
|
require: public
|
||||||
bblanchon/arduinojson:
|
bblanchon/arduinojson:
|
||||||
version: "^7.3.1"
|
version: "^7.4.2"
|
||||||
require: public
|
require: public
|
||||||
examples:
|
examples:
|
||||||
- path: ./idf_component_examples/catchall
|
- path: ./idf_component_examples/catchall
|
||||||
|
@@ -78,7 +78,7 @@ static const size_t htmlContentLength = strlen_P(htmlContent);
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -50,7 +50,7 @@ static AsyncEventSource events("/events");
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -17,7 +17,7 @@ static AsyncWebSocket ws("/ws");
|
|||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ESPAsyncWebServer",
|
"name": "ESPAsyncWebServer",
|
||||||
"version": "3.7.5",
|
"version": "3.8.0",
|
||||||
"description": "Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040. Supports: WebSocket, SSE, Authentication, Arduino Json 7, File Upload, Static File serving, URL Rewrite, URL Redirect, etc.",
|
"description": "Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040. Supports: WebSocket, SSE, Authentication, Arduino Json 7, File Upload, Static File serving, URL Rewrite, URL Redirect, etc.",
|
||||||
"keywords": "http,async,websocket,webserver",
|
"keywords": "http,async,websocket,webserver",
|
||||||
"homepage": "https://github.com/ESP32Async/ESPAsyncWebServer",
|
"homepage": "https://github.com/ESP32Async/ESPAsyncWebServer",
|
||||||
@@ -18,14 +18,18 @@
|
|||||||
"platforms": [
|
"platforms": [
|
||||||
"espressif32",
|
"espressif32",
|
||||||
"espressif8266",
|
"espressif8266",
|
||||||
"raspberrypi"
|
"raspberrypi",
|
||||||
|
"libretiny"
|
||||||
],
|
],
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
{
|
{
|
||||||
"owner": "ESP32Async",
|
"owner": "ESP32Async",
|
||||||
"name": "AsyncTCP",
|
"name": "AsyncTCP",
|
||||||
"version": "^3.3.8",
|
"version": "^3.4.7",
|
||||||
"platforms": "espressif32"
|
"platforms": [
|
||||||
|
"espressif32",
|
||||||
|
"libretiny"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"owner": "ESP32Async",
|
"owner": "ESP32Async",
|
@@ -1,6 +1,6 @@
|
|||||||
name=ESP Async WebServer
|
name=ESP Async WebServer
|
||||||
includes=ESPAsyncWebServer.h
|
includes=ESPAsyncWebServer.h
|
||||||
version=3.7.5
|
version=3.8.0
|
||||||
author=ESP32Async
|
author=ESP32Async
|
||||||
maintainer=ESP32Async
|
maintainer=ESP32Async
|
||||||
sentence=Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040
|
sentence=Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[env]
|
[env]
|
||||||
framework = arduino
|
framework = arduino
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30-2/platform-espressif32.zip
|
||||||
build_flags =
|
build_flags =
|
||||||
-Og
|
-Og
|
||||||
-Wall -Wextra
|
-Wall -Wextra
|
||||||
@@ -17,7 +17,7 @@ monitor_filters = esp32_exception_decoder, log2file
|
|||||||
lib_compat_mode = strict
|
lib_compat_mode = strict
|
||||||
lib_ldf_mode = chain
|
lib_ldf_mode = chain
|
||||||
lib_deps =
|
lib_deps =
|
||||||
ESP32Async/AsyncTCP @ 3.3.8
|
ESP32Async/AsyncTCP @ 3.4.7
|
||||||
ESP32Async/ESpAsyncWebServer @ 3.7.0
|
ESP32Async/ESpAsyncWebServer @ 3.7.0
|
||||||
|
|
||||||
custom_sdkconfig = CONFIG_LWIP_MAX_ACTIVE_TCP=32
|
custom_sdkconfig = CONFIG_LWIP_MAX_ACTIVE_TCP=32
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
default_envs = arduino-2, arduino-3, esp8266, raspberrypi
|
default_envs = arduino-2, arduino-3, esp8266, raspberrypi
|
||||||
lib_dir = .
|
lib_dir = .
|
||||||
; src_dir = examples/AsyncResponseStream
|
; src_dir = examples/AsyncResponseStream
|
||||||
|
; src_dir = examples/AsyncTunnel
|
||||||
; src_dir = examples/Auth
|
; src_dir = examples/Auth
|
||||||
; src_dir = examples/CaptivePortal
|
; src_dir = examples/CaptivePortal
|
||||||
; src_dir = examples/CatchAllHandler
|
; src_dir = examples/CatchAllHandler
|
||||||
@@ -37,7 +38,7 @@ src_dir = examples/PerfTests
|
|||||||
|
|
||||||
[env]
|
[env]
|
||||||
framework = arduino
|
framework = arduino
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30-2/platform-espressif32.zip
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
build_flags =
|
build_flags =
|
||||||
-Og
|
-Og
|
||||||
@@ -58,24 +59,26 @@ monitor_filters = esp32_exception_decoder, log2file
|
|||||||
lib_compat_mode = strict
|
lib_compat_mode = strict
|
||||||
lib_ldf_mode = chain
|
lib_ldf_mode = chain
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson @ 7.3.1
|
bblanchon/ArduinoJson @ 7.4.2
|
||||||
ESP32Async/AsyncTCP @ 3.3.8
|
ESP32Async/AsyncTCP @ 3.4.7
|
||||||
board_build.partitions = partitions-4MB.csv
|
board_build.partitions = partitions-4MB.csv
|
||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
|
|
||||||
[env:arduino-2]
|
[env:arduino-2]
|
||||||
platform = espressif32@6.10.0
|
platform = espressif32@6.12.0
|
||||||
|
|
||||||
[env:arduino-3]
|
[env:arduino-3]
|
||||||
|
; board = esp32-p4
|
||||||
|
; board = esp32-h2-devkitm-1
|
||||||
|
|
||||||
[env:arduino-3-latest]
|
[env:arduino-rc]
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20-rc2/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20-rc2/platform-espressif32.zip
|
||||||
|
|
||||||
[env:arduino-3-no-json]
|
[env:arduino-3-no-json]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
ESP32Async/AsyncTCP @ 3.3.8
|
ESP32Async/AsyncTCP @ 3.4.7
|
||||||
|
|
||||||
[env:arduino-3-latest-asynctcp]
|
[env:arduino-rc-asynctcp]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
https://github.com/ESP32Async/AsyncTCP
|
https://github.com/ESP32Async/AsyncTCP
|
||||||
|
|
||||||
@@ -93,7 +96,7 @@ platform = espressif8266
|
|||||||
; board = huzzah
|
; board = huzzah
|
||||||
board = d1_mini
|
board = d1_mini
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson @ 7.3.1
|
bblanchon/ArduinoJson @ 7.4.2
|
||||||
ESP32Async/ESPAsyncTCP @ 2.0.0
|
ESP32Async/ESPAsyncTCP @ 2.0.0
|
||||||
|
|
||||||
[env:raspberrypi]
|
[env:raspberrypi]
|
||||||
@@ -108,25 +111,36 @@ lib_ignore =
|
|||||||
build_flags = ${env.build_flags}
|
build_flags = ${env.build_flags}
|
||||||
-Wno-missing-field-initializers
|
-Wno-missing-field-initializers
|
||||||
|
|
||||||
|
[env:libretiny]
|
||||||
|
platform = libretiny @ ^1.9.1
|
||||||
|
board = generic-bk7231n-qfn32-tuya
|
||||||
|
; board = generic-rtl8710bn-2mb-788k
|
||||||
|
lib_compat_mode = off
|
||||||
|
lib_deps =
|
||||||
|
ESP32Async/AsyncTCP @ 3.4.3
|
||||||
|
; use FreeRTOS v9.0.0 for RTL8710BN
|
||||||
|
; (BK7231 already uses it)
|
||||||
|
custom_versions.freertos = 9.0.0
|
||||||
|
|
||||||
; CI
|
; CI
|
||||||
|
|
||||||
[env:ci-arduino-2]
|
[env:ci-arduino-2]
|
||||||
platform = espressif32@6.10.0
|
platform = espressif32@6.12.0
|
||||||
board = ${sysenv.PIO_BOARD}
|
board = ${sysenv.PIO_BOARD}
|
||||||
|
|
||||||
[env:ci-arduino-3]
|
[env:ci-arduino-3]
|
||||||
board = ${sysenv.PIO_BOARD}
|
board = ${sysenv.PIO_BOARD}
|
||||||
|
|
||||||
[env:ci-arduino-3-latest]
|
[env:ci-arduino-rc]
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20-rc2/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20-rc2/platform-espressif32.zip
|
||||||
board = ${sysenv.PIO_BOARD}
|
board = ${sysenv.PIO_BOARD}
|
||||||
|
|
||||||
[env:ci-arduino-3-no-json]
|
[env:ci-arduino-3-no-json]
|
||||||
board = ${sysenv.PIO_BOARD}
|
board = ${sysenv.PIO_BOARD}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
ESP32Async/AsyncTCP @ 3.3.8
|
ESP32Async/AsyncTCP @ 3.4.7
|
||||||
|
|
||||||
[env:ci-arduino-3-latest-asynctcp]
|
[env:ci-arduino-rc-asynctcp]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
https://github.com/ESP32Async/AsyncTCP
|
https://github.com/ESP32Async/AsyncTCP
|
||||||
|
|
||||||
@@ -139,7 +153,7 @@ build_flags = ${env.build_flags}
|
|||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
board = ${sysenv.PIO_BOARD}
|
board = ${sysenv.PIO_BOARD}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson @ 7.3.1
|
bblanchon/ArduinoJson @ 7.4.2
|
||||||
ESP32Async/ESPAsyncTCP @ 2.0.0
|
ESP32Async/ESPAsyncTCP @ 2.0.0
|
||||||
|
|
||||||
[env:ci-raspberrypi]
|
[env:ci-raspberrypi]
|
||||||
@@ -153,3 +167,13 @@ lib_ignore =
|
|||||||
lwIP_ESPHost
|
lwIP_ESPHost
|
||||||
build_flags = ${env.build_flags}
|
build_flags = ${env.build_flags}
|
||||||
-Wno-missing-field-initializers
|
-Wno-missing-field-initializers
|
||||||
|
|
||||||
|
[env:ci-libretiny]
|
||||||
|
platform = libretiny @ ^1.9.1
|
||||||
|
board = ${sysenv.PIO_BOARD}
|
||||||
|
lib_compat_mode = off
|
||||||
|
lib_deps =
|
||||||
|
; add DNS server library for LibreTiny
|
||||||
|
DNSServer
|
||||||
|
ESP32Async/AsyncTCP @ 3.4.3
|
||||||
|
custom_versions.freertos = 9.0.0
|
||||||
|
@@ -193,7 +193,7 @@ AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest *request, A
|
|||||||
|
|
||||||
AsyncEventSourceClient::~AsyncEventSourceClient() {
|
AsyncEventSourceClient::~AsyncEventSourceClient() {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_lockmq);
|
std::lock_guard<std::recursive_mutex> lock(_lockmq);
|
||||||
#endif
|
#endif
|
||||||
_messageQueue.clear();
|
_messageQueue.clear();
|
||||||
close();
|
close();
|
||||||
@@ -211,7 +211,7 @@ bool AsyncEventSourceClient::_queueMessage(const char *message, size_t len) {
|
|||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
// length() is not thread-safe, thus acquiring the lock before this call..
|
// length() is not thread-safe, thus acquiring the lock before this call..
|
||||||
std::lock_guard<std::mutex> lock(_lockmq);
|
std::lock_guard<std::recursive_mutex> lock(_lockmq);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_messageQueue.emplace_back(message, len);
|
_messageQueue.emplace_back(message, len);
|
||||||
@@ -241,7 +241,7 @@ bool AsyncEventSourceClient::_queueMessage(AsyncEvent_SharedData_t &&msg) {
|
|||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
// length() is not thread-safe, thus acquiring the lock before this call..
|
// length() is not thread-safe, thus acquiring the lock before this call..
|
||||||
std::lock_guard<std::mutex> lock(_lockmq);
|
std::lock_guard<std::recursive_mutex> lock(_lockmq);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_messageQueue.emplace_back(std::move(msg));
|
_messageQueue.emplace_back(std::move(msg));
|
||||||
@@ -261,7 +261,7 @@ bool AsyncEventSourceClient::_queueMessage(AsyncEvent_SharedData_t &&msg) {
|
|||||||
void AsyncEventSourceClient::_onAck(size_t len __attribute__((unused)), uint32_t time __attribute__((unused))) {
|
void AsyncEventSourceClient::_onAck(size_t len __attribute__((unused)), uint32_t time __attribute__((unused))) {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
// Same here, acquiring the lock early
|
// Same here, acquiring the lock early
|
||||||
std::lock_guard<std::mutex> lock(_lockmq);
|
std::lock_guard<std::recursive_mutex> lock(_lockmq);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// adjust in-flight len
|
// adjust in-flight len
|
||||||
@@ -290,7 +290,7 @@ void AsyncEventSourceClient::_onPoll() {
|
|||||||
if (_messageQueue.size()) {
|
if (_messageQueue.size()) {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
// Same here, acquiring the lock early
|
// Same here, acquiring the lock early
|
||||||
std::lock_guard<std::mutex> lock(_lockmq);
|
std::lock_guard<std::recursive_mutex> lock(_lockmq);
|
||||||
#endif
|
#endif
|
||||||
_runQueue();
|
_runQueue();
|
||||||
}
|
}
|
||||||
@@ -367,7 +367,7 @@ void AsyncEventSource::_addClient(AsyncEventSourceClient *client) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
|
||||||
#endif
|
#endif
|
||||||
_clients.emplace_back(client);
|
_clients.emplace_back(client);
|
||||||
if (_connectcb) {
|
if (_connectcb) {
|
||||||
@@ -382,7 +382,7 @@ void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient *client) {
|
|||||||
_disconnectcb(client);
|
_disconnectcb(client);
|
||||||
}
|
}
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
|
||||||
#endif
|
#endif
|
||||||
for (auto i = _clients.begin(); i != _clients.end(); ++i) {
|
for (auto i = _clients.begin(); i != _clients.end(); ++i) {
|
||||||
if (i->get() == client) {
|
if (i->get() == client) {
|
||||||
@@ -398,10 +398,15 @@ void AsyncEventSource::close() {
|
|||||||
// iterator should remain valid even when AsyncEventSource::_handleDisconnect()
|
// iterator should remain valid even when AsyncEventSource::_handleDisconnect()
|
||||||
// is called very early
|
// is called very early
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
|
||||||
#endif
|
#endif
|
||||||
for (const auto &c : _clients) {
|
for (const auto &c : _clients) {
|
||||||
if (c->connected()) {
|
if (c->connected()) {
|
||||||
|
/**
|
||||||
|
* @brief: Fix self-deadlock by using recursive_mutex instead.
|
||||||
|
* Due to c->close() shall call the callback function _onDisconnect()
|
||||||
|
* The calling flow _onDisconnect() --> _handleDisconnect() --> deadlock
|
||||||
|
*/
|
||||||
c->close();
|
c->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -412,7 +417,7 @@ size_t AsyncEventSource::avgPacketsWaiting() const {
|
|||||||
size_t aql = 0;
|
size_t aql = 0;
|
||||||
uint32_t nConnectedClients = 0;
|
uint32_t nConnectedClients = 0;
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
|
||||||
#endif
|
#endif
|
||||||
if (!_clients.size()) {
|
if (!_clients.size()) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -430,7 +435,7 @@ size_t AsyncEventSource::avgPacketsWaiting() const {
|
|||||||
AsyncEventSource::SendStatus AsyncEventSource::send(const char *message, const char *event, uint32_t id, uint32_t reconnect) {
|
AsyncEventSource::SendStatus AsyncEventSource::send(const char *message, const char *event, uint32_t id, uint32_t reconnect) {
|
||||||
AsyncEvent_SharedData_t shared_msg = std::make_shared<String>(generateEventMessage(message, event, id, reconnect));
|
AsyncEvent_SharedData_t shared_msg = std::make_shared<String>(generateEventMessage(message, event, id, reconnect));
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
|
||||||
#endif
|
#endif
|
||||||
size_t hits = 0;
|
size_t hits = 0;
|
||||||
size_t miss = 0;
|
size_t miss = 0;
|
||||||
@@ -446,7 +451,7 @@ AsyncEventSource::SendStatus AsyncEventSource::send(const char *message, const c
|
|||||||
|
|
||||||
size_t AsyncEventSource::count() const {
|
size_t AsyncEventSource::count() const {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
|
||||||
#endif
|
#endif
|
||||||
size_t n_clients{0};
|
size_t n_clients{0};
|
||||||
for (const auto &i : _clients) {
|
for (const auto &i : _clients) {
|
||||||
|
@@ -6,8 +6,13 @@
|
|||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
|
#ifdef LIBRETINY
|
||||||
|
#ifdef round
|
||||||
|
#undef round
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#ifndef SSE_MAX_QUEUED_MESSAGES
|
#ifndef SSE_MAX_QUEUED_MESSAGES
|
||||||
#define SSE_MAX_QUEUED_MESSAGES 32
|
#define SSE_MAX_QUEUED_MESSAGES 32
|
||||||
@@ -129,7 +134,7 @@ private:
|
|||||||
size_t _max_inflight{SSE_MAX_INFLIGH}; // max num of unacknowledged bytes that could be written to socket buffer
|
size_t _max_inflight{SSE_MAX_INFLIGH}; // max num of unacknowledged bytes that could be written to socket buffer
|
||||||
std::list<AsyncEventSourceMessage> _messageQueue;
|
std::list<AsyncEventSourceMessage> _messageQueue;
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
mutable std::mutex _lockmq;
|
mutable std::recursive_mutex _lockmq;
|
||||||
#endif
|
#endif
|
||||||
bool _queueMessage(const char *message, size_t len);
|
bool _queueMessage(const char *message, size_t len);
|
||||||
bool _queueMessage(AsyncEvent_SharedData_t &&msg);
|
bool _queueMessage(AsyncEvent_SharedData_t &&msg);
|
||||||
@@ -230,7 +235,7 @@ private:
|
|||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
// Same as for individual messages, protect mutations of _clients list
|
// Same as for individual messages, protect mutations of _clients list
|
||||||
// since simultaneous access from different tasks is possible
|
// since simultaneous access from different tasks is possible
|
||||||
mutable std::mutex _client_queue_lock;
|
mutable std::recursive_mutex _client_queue_lock;
|
||||||
#endif
|
#endif
|
||||||
ArEventHandlerFunction _connectcb = nullptr;
|
ArEventHandlerFunction _connectcb = nullptr;
|
||||||
ArEventHandlerFunction _disconnectcb = nullptr;
|
ArEventHandlerFunction _disconnectcb = nullptr;
|
||||||
|
@@ -113,43 +113,64 @@ bool AsyncCallbackJsonWebHandler::canHandle(AsyncWebServerRequest *request) cons
|
|||||||
|
|
||||||
void AsyncCallbackJsonWebHandler::handleRequest(AsyncWebServerRequest *request) {
|
void AsyncCallbackJsonWebHandler::handleRequest(AsyncWebServerRequest *request) {
|
||||||
if (_onRequest) {
|
if (_onRequest) {
|
||||||
|
// GET request:
|
||||||
if (request->method() == HTTP_GET) {
|
if (request->method() == HTTP_GET) {
|
||||||
JsonVariant json;
|
JsonVariant json;
|
||||||
_onRequest(request, json);
|
_onRequest(request, json);
|
||||||
return;
|
return;
|
||||||
} else if (request->_tempObject != NULL) {
|
}
|
||||||
|
|
||||||
|
// POST / PUT / ... requests:
|
||||||
|
// check if JSON body is too large, if it is, don't deserialize
|
||||||
|
if (request->contentLength() > _maxContentLength) {
|
||||||
|
#ifdef ESP32
|
||||||
|
log_e("Content length exceeds maximum allowed");
|
||||||
|
#endif
|
||||||
|
request->send(413);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->_tempObject == NULL) {
|
||||||
|
// there is no body
|
||||||
|
request->send(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if ARDUINOJSON_VERSION_MAJOR == 5
|
#if ARDUINOJSON_VERSION_MAJOR == 5
|
||||||
DynamicJsonBuffer jsonBuffer;
|
DynamicJsonBuffer jsonBuffer;
|
||||||
JsonVariant json = jsonBuffer.parse((uint8_t *)(request->_tempObject));
|
JsonVariant json = jsonBuffer.parse((const char *)request->_tempObject);
|
||||||
if (json.success()) {
|
if (json.success()) {
|
||||||
#elif ARDUINOJSON_VERSION_MAJOR == 6
|
#elif ARDUINOJSON_VERSION_MAJOR == 6
|
||||||
DynamicJsonDocument jsonBuffer(this->maxJsonBufferSize);
|
DynamicJsonDocument jsonBuffer(this->maxJsonBufferSize);
|
||||||
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject));
|
DeserializationError error = deserializeJson(jsonBuffer, (const char *)request->_tempObject);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
JsonVariant json = jsonBuffer.as<JsonVariant>();
|
JsonVariant json = jsonBuffer.as<JsonVariant>();
|
||||||
#else
|
#else
|
||||||
JsonDocument jsonBuffer;
|
JsonDocument jsonBuffer;
|
||||||
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject));
|
DeserializationError error = deserializeJson(jsonBuffer, (const char *)request->_tempObject);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
JsonVariant json = jsonBuffer.as<JsonVariant>();
|
JsonVariant json = jsonBuffer.as<JsonVariant>();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_onRequest(request, json);
|
_onRequest(request, json);
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
request->send(_contentLength > _maxContentLength ? 413 : 400);
|
|
||||||
} else {
|
} else {
|
||||||
request->send(500);
|
// error parsing the body
|
||||||
|
request->send(400);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncCallbackJsonWebHandler::handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
|
void AsyncCallbackJsonWebHandler::handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
|
||||||
if (_onRequest) {
|
if (_onRequest) {
|
||||||
_contentLength = total;
|
// ignore callback if size is larger than maxContentLength
|
||||||
if (total > 0 && request->_tempObject == NULL && total < _maxContentLength) {
|
if (total > _maxContentLength) {
|
||||||
request->_tempObject = malloc(total);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
|
// this check allows request->_tempObject to be initialized from a middleware
|
||||||
|
if (request->_tempObject == NULL) {
|
||||||
|
request->_tempObject = calloc(total + 1, sizeof(uint8_t)); // null-terminated string
|
||||||
if (request->_tempObject == NULL) {
|
if (request->_tempObject == NULL) {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
log_e("Failed to allocate");
|
log_e("Failed to allocate");
|
||||||
@@ -158,8 +179,11 @@ void AsyncCallbackJsonWebHandler::handleBody(AsyncWebServerRequest *request, uin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (request->_tempObject != NULL) {
|
if (request->_tempObject != NULL) {
|
||||||
memcpy((uint8_t *)(request->_tempObject) + index, data, len);
|
uint8_t *buffer = (uint8_t *)request->_tempObject;
|
||||||
|
memcpy(buffer + index, data, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,8 +4,14 @@
|
|||||||
#ifndef ASYNC_JSON_H_
|
#ifndef ASYNC_JSON_H_
|
||||||
#define ASYNC_JSON_H_
|
#define ASYNC_JSON_H_
|
||||||
|
|
||||||
|
#if __has_include("ArduinoJson.h")
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
#if ARDUINOJSON_VERSION_MAJOR >= 5
|
||||||
#define ASYNC_JSON_SUPPORT 1
|
#define ASYNC_JSON_SUPPORT 1
|
||||||
|
#else
|
||||||
|
#define ASYNC_JSON_SUPPORT 0
|
||||||
|
#endif // ARDUINOJSON_VERSION_MAJOR >= 5
|
||||||
|
#endif // __has_include("ArduinoJson.h")
|
||||||
|
|
||||||
#if ASYNC_JSON_SUPPORT == 1
|
#if ASYNC_JSON_SUPPORT == 1
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
@@ -73,7 +79,6 @@ protected:
|
|||||||
String _uri;
|
String _uri;
|
||||||
WebRequestMethodComposite _method;
|
WebRequestMethodComposite _method;
|
||||||
ArJsonRequestHandlerFunction _onRequest;
|
ArJsonRequestHandlerFunction _onRequest;
|
||||||
size_t _contentLength;
|
|
||||||
#if ARDUINOJSON_VERSION_MAJOR == 6
|
#if ARDUINOJSON_VERSION_MAJOR == 6
|
||||||
size_t maxJsonBufferSize;
|
size_t maxJsonBufferSize;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -3,30 +3,32 @@
|
|||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
AsyncWebHeader::AsyncWebHeader(const String &data) {
|
const AsyncWebHeader AsyncWebHeader::parse(const char *data) {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers
|
||||||
|
// In HTTP/1.X, a header is a case-insensitive name followed by a colon, then optional whitespace which will be ignored, and finally by its value
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return;
|
return AsyncWebHeader(); // nullptr
|
||||||
}
|
}
|
||||||
int index = data.indexOf(':');
|
if (data[0] == '\0') {
|
||||||
if (index < 0) {
|
return AsyncWebHeader(); // empty string
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
_name = data.substring(0, index);
|
if (strchr(data, '\n') || strchr(data, '\r')) {
|
||||||
_value = data.substring(index + 2);
|
return AsyncWebHeader(); // Invalid header format
|
||||||
}
|
}
|
||||||
|
const char *colon = strchr(data, ':');
|
||||||
String AsyncWebHeader::toString() const {
|
if (!colon) {
|
||||||
String str;
|
return AsyncWebHeader(); // separator not found
|
||||||
if (str.reserve(_name.length() + _value.length() + 2)) {
|
|
||||||
str.concat(_name);
|
|
||||||
str.concat((char)0x3a);
|
|
||||||
str.concat((char)0x20);
|
|
||||||
str.concat(_value);
|
|
||||||
str.concat(asyncsrv::T_rn);
|
|
||||||
} else {
|
|
||||||
#ifdef ESP32
|
|
||||||
log_e("Failed to allocate");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return str;
|
if (colon == data) {
|
||||||
|
return AsyncWebHeader(); // Header name cannot be empty
|
||||||
|
}
|
||||||
|
const char *startOfValue = colon + 1; // Skip the colon
|
||||||
|
// skip one optional whitespace after the colon
|
||||||
|
if (*startOfValue == ' ') {
|
||||||
|
startOfValue++;
|
||||||
|
}
|
||||||
|
String name;
|
||||||
|
name.reserve(colon - data);
|
||||||
|
name.concat(data, colon - data);
|
||||||
|
return AsyncWebHeader(name, String(startOfValue));
|
||||||
}
|
}
|
||||||
|
85
src/AsyncWebServerRequest.cpp
Normal file
85
src/AsyncWebServerRequest.cpp
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends a file from the filesystem to the client, with optional gzip compression and ETag-based caching.
|
||||||
|
*
|
||||||
|
* This method serves files over HTTP from the provided filesystem. If a compressed version of the file
|
||||||
|
* (with a `.gz` extension) exists and uncompressed version does not exist, it serves the compressed file.
|
||||||
|
* It also handles ETag caching using the CRC32 value from the gzip trailer, responding with `304 Not Modified`
|
||||||
|
* if the client's `If-None-Match` header matches the generated ETag.
|
||||||
|
*
|
||||||
|
* @param fs Reference to the filesystem (SPIFFS, LittleFS, etc.).
|
||||||
|
* @param path Path to the file to be served.
|
||||||
|
* @param contentType Optional MIME type of the file to be sent.
|
||||||
|
* If contentType is "" it will be obtained from the file extension
|
||||||
|
* @param download If true, forces the file to be sent as a download.
|
||||||
|
* @param callback Optional template processor for dynamic content generation.
|
||||||
|
* Templates will not be processed in compressed files.
|
||||||
|
*
|
||||||
|
* @note If neither the file nor its compressed version exists, responds with `404 Not Found`.
|
||||||
|
*/
|
||||||
|
void AsyncWebServerRequest::send(FS &fs, const String &path, const char *contentType, bool download, AwsTemplateProcessor callback) {
|
||||||
|
// Check uncompressed file first
|
||||||
|
if (fs.exists(path)) {
|
||||||
|
send(beginResponse(fs, path, contentType, download, callback));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle compressed version
|
||||||
|
const String gzPath = path + asyncsrv::T__gz;
|
||||||
|
File gzFile = fs.open(gzPath, fs::FileOpenMode::read);
|
||||||
|
|
||||||
|
// Compressed file not found or invalid
|
||||||
|
if (!gzFile.seek(gzFile.size() - 8)) {
|
||||||
|
send(404);
|
||||||
|
gzFile.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ETag validation
|
||||||
|
if (this->hasHeader(asyncsrv::T_INM)) {
|
||||||
|
// Generate server ETag from CRC in gzip trailer
|
||||||
|
uint8_t crcInTrailer[4];
|
||||||
|
gzFile.read(crcInTrailer, 4);
|
||||||
|
char serverETag[9];
|
||||||
|
_getEtag(crcInTrailer, serverETag);
|
||||||
|
|
||||||
|
// Compare with client's ETag
|
||||||
|
const AsyncWebHeader *inmHeader = this->getHeader(asyncsrv::T_INM);
|
||||||
|
if (inmHeader && inmHeader->value() == serverETag) {
|
||||||
|
gzFile.close();
|
||||||
|
this->send(304); // Not Modified
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send compressed file response
|
||||||
|
gzFile.close();
|
||||||
|
send(beginResponse(fs, path, contentType, download, callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generates an ETag string from a 4-byte trailer
|
||||||
|
*
|
||||||
|
* This function converts a 4-byte array into a hexadecimal ETag string enclosed in quotes.
|
||||||
|
*
|
||||||
|
* @param trailer[4] Input array of 4 bytes to convert to hexadecimal
|
||||||
|
* @param serverETag Output buffer to store the ETag
|
||||||
|
* Must be pre-allocated with minimum 9 bytes (8 hex + 1 null terminator)
|
||||||
|
*/
|
||||||
|
void AsyncWebServerRequest::_getEtag(uint8_t trailer[4], char *serverETag) {
|
||||||
|
static constexpr char hexChars[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
uint32_t data;
|
||||||
|
memcpy(&data, trailer, 4);
|
||||||
|
|
||||||
|
serverETag[0] = hexChars[(data >> 4) & 0x0F];
|
||||||
|
serverETag[1] = hexChars[data & 0x0F];
|
||||||
|
serverETag[2] = hexChars[(data >> 12) & 0x0F];
|
||||||
|
serverETag[3] = hexChars[(data >> 8) & 0x0F];
|
||||||
|
serverETag[4] = hexChars[(data >> 20) & 0x0F];
|
||||||
|
serverETag[5] = hexChars[(data >> 16) & 0x0F];
|
||||||
|
serverETag[6] = hexChars[(data >> 28)];
|
||||||
|
serverETag[7] = hexChars[(data >> 24) & 0x0F];
|
||||||
|
serverETag[8] = '\0';
|
||||||
|
}
|
@@ -10,9 +10,9 @@ extern "C" {
|
|||||||
/** Major version number (X.x.x) */
|
/** Major version number (X.x.x) */
|
||||||
#define ASYNCWEBSERVER_VERSION_MAJOR 3
|
#define ASYNCWEBSERVER_VERSION_MAJOR 3
|
||||||
/** Minor version number (x.X.x) */
|
/** Minor version number (x.X.x) */
|
||||||
#define ASYNCWEBSERVER_VERSION_MINOR 7
|
#define ASYNCWEBSERVER_VERSION_MINOR 8
|
||||||
/** Patch version number (x.x.X) */
|
/** Patch version number (x.x.X) */
|
||||||
#define ASYNCWEBSERVER_VERSION_PATCH 5
|
#define ASYNCWEBSERVER_VERSION_PATCH 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Macro to convert version number into an integer
|
* Macro to convert version number into an integer
|
||||||
|
@@ -17,6 +17,8 @@
|
|||||||
#include <rom/ets_sys.h>
|
#include <rom/ets_sys.h>
|
||||||
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350) || defined(ESP8266)
|
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350) || defined(ESP8266)
|
||||||
#include <Hash.h>
|
#include <Hash.h>
|
||||||
|
#elif defined(LIBRETINY)
|
||||||
|
#include <mbedtls/sha1.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace asyncsrv;
|
using namespace asyncsrv;
|
||||||
@@ -118,6 +120,11 @@ size_t webSocketSendFrame(AsyncClient *client, bool final, uint8_t opcode, bool
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t AsyncWebSocketControl::send(AsyncClient *client) {
|
||||||
|
_finished = true;
|
||||||
|
return webSocketSendFrame(client, true, _opcode & 0x0F, _mask, _data, _len);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AsyncWebSocketMessageBuffer
|
* AsyncWebSocketMessageBuffer
|
||||||
*/
|
*/
|
||||||
@@ -144,65 +151,6 @@ bool AsyncWebSocketMessageBuffer::reserve(size_t size) {
|
|||||||
return _buffer->capacity() >= size;
|
return _buffer->capacity() >= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Control Frame
|
|
||||||
*/
|
|
||||||
|
|
||||||
class AsyncWebSocketControl {
|
|
||||||
private:
|
|
||||||
uint8_t _opcode;
|
|
||||||
uint8_t *_data;
|
|
||||||
size_t _len;
|
|
||||||
bool _mask;
|
|
||||||
bool _finished;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AsyncWebSocketControl(uint8_t opcode, const uint8_t *data = NULL, size_t len = 0, bool mask = false)
|
|
||||||
: _opcode(opcode), _len(len), _mask(len && mask), _finished(false) {
|
|
||||||
if (data == NULL) {
|
|
||||||
_len = 0;
|
|
||||||
}
|
|
||||||
if (_len) {
|
|
||||||
if (_len > 125) {
|
|
||||||
_len = 125;
|
|
||||||
}
|
|
||||||
|
|
||||||
_data = (uint8_t *)malloc(_len);
|
|
||||||
|
|
||||||
if (_data == NULL) {
|
|
||||||
#ifdef ESP32
|
|
||||||
log_e("Failed to allocate");
|
|
||||||
#endif
|
|
||||||
_len = 0;
|
|
||||||
} else {
|
|
||||||
memcpy(_data, data, len);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_data = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~AsyncWebSocketControl() {
|
|
||||||
if (_data != NULL) {
|
|
||||||
free(_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool finished() const {
|
|
||||||
return _finished;
|
|
||||||
}
|
|
||||||
uint8_t opcode() {
|
|
||||||
return _opcode;
|
|
||||||
}
|
|
||||||
uint8_t len() {
|
|
||||||
return _len + 2;
|
|
||||||
}
|
|
||||||
size_t send(AsyncClient *client) {
|
|
||||||
_finished = true;
|
|
||||||
return webSocketSendFrame(client, true, _opcode & 0x0F, _mask, _data, _len);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AsyncWebSocketMessage Message
|
* AsyncWebSocketMessage Message
|
||||||
*/
|
*/
|
||||||
@@ -333,7 +281,7 @@ AsyncWebSocketClient::AsyncWebSocketClient(AsyncWebServerRequest *request, Async
|
|||||||
AsyncWebSocketClient::~AsyncWebSocketClient() {
|
AsyncWebSocketClient::~AsyncWebSocketClient() {
|
||||||
{
|
{
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::lock_guard<std::recursive_mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
_messageQueue.clear();
|
_messageQueue.clear();
|
||||||
_controlQueue.clear();
|
_controlQueue.clear();
|
||||||
@@ -351,7 +299,7 @@ void AsyncWebSocketClient::_onAck(size_t len, uint32_t time) {
|
|||||||
_lastMessageTime = millis();
|
_lastMessageTime = millis();
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::unique_lock<std::recursive_mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!_controlQueue.empty()) {
|
if (!_controlQueue.empty()) {
|
||||||
@@ -362,6 +310,14 @@ void AsyncWebSocketClient::_onAck(size_t len, uint32_t time) {
|
|||||||
_controlQueue.pop_front();
|
_controlQueue.pop_front();
|
||||||
_status = WS_DISCONNECTED;
|
_status = WS_DISCONNECTED;
|
||||||
if (_client) {
|
if (_client) {
|
||||||
|
#ifdef ESP32
|
||||||
|
/*
|
||||||
|
Unlocking has to be called before return execution otherwise std::unique_lock ::~unique_lock() will get an exception pthread_mutex_unlock.
|
||||||
|
Due to _client->close(true) shall call the callback function _onDisconnect()
|
||||||
|
The calling flow _onDisconnect() --> _handleDisconnect() --> ~AsyncWebSocketClient()
|
||||||
|
*/
|
||||||
|
lock.unlock();
|
||||||
|
#endif
|
||||||
_client->close(true);
|
_client->close(true);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -385,7 +341,7 @@ void AsyncWebSocketClient::_onPoll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::unique_lock<std::mutex> lock(_lock);
|
std::unique_lock<std::recursive_mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
if (_client && _client->canSend() && (!_controlQueue.empty() || !_messageQueue.empty())) {
|
if (_client && _client->canSend() && (!_controlQueue.empty() || !_messageQueue.empty())) {
|
||||||
_runQueue();
|
_runQueue();
|
||||||
@@ -415,21 +371,21 @@ void AsyncWebSocketClient::_runQueue() {
|
|||||||
|
|
||||||
bool AsyncWebSocketClient::queueIsFull() const {
|
bool AsyncWebSocketClient::queueIsFull() const {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::lock_guard<std::recursive_mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
return (_messageQueue.size() >= WS_MAX_QUEUED_MESSAGES) || (_status != WS_CONNECTED);
|
return (_messageQueue.size() >= WS_MAX_QUEUED_MESSAGES) || (_status != WS_CONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AsyncWebSocketClient::queueLen() const {
|
size_t AsyncWebSocketClient::queueLen() const {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::lock_guard<std::recursive_mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
return _messageQueue.size();
|
return _messageQueue.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncWebSocketClient::canSend() const {
|
bool AsyncWebSocketClient::canSend() const {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::lock_guard<std::recursive_mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
return _messageQueue.size() < WS_MAX_QUEUED_MESSAGES;
|
return _messageQueue.size() < WS_MAX_QUEUED_MESSAGES;
|
||||||
}
|
}
|
||||||
@@ -440,7 +396,7 @@ bool AsyncWebSocketClient::_queueControl(uint8_t opcode, const uint8_t *data, si
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::lock_guard<std::recursive_mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_controlQueue.emplace_back(opcode, data, len, mask);
|
_controlQueue.emplace_back(opcode, data, len, mask);
|
||||||
@@ -458,7 +414,7 @@ bool AsyncWebSocketClient::_queueMessage(AsyncWebSocketSharedBuffer buffer, uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::unique_lock<std::recursive_mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_messageQueue.size() >= WS_MAX_QUEUED_MESSAGES) {
|
if (_messageQueue.size() >= WS_MAX_QUEUED_MESSAGES) {
|
||||||
@@ -466,6 +422,14 @@ bool AsyncWebSocketClient::_queueMessage(AsyncWebSocketSharedBuffer buffer, uint
|
|||||||
_status = WS_DISCONNECTED;
|
_status = WS_DISCONNECTED;
|
||||||
|
|
||||||
if (_client) {
|
if (_client) {
|
||||||
|
#ifdef ESP32
|
||||||
|
/*
|
||||||
|
Unlocking has to be called before return execution otherwise std::unique_lock ::~unique_lock() will get an exception pthread_mutex_unlock.
|
||||||
|
Due to _client->close(true) shall call the callback function _onDisconnect()
|
||||||
|
The calling flow _onDisconnect() --> _handleDisconnect() --> ~AsyncWebSocketClient()
|
||||||
|
*/
|
||||||
|
lock.unlock();
|
||||||
|
#endif
|
||||||
_client->close(true);
|
_client->close(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,6 +515,7 @@ void AsyncWebSocketClient::_onTimeout(uint32_t time) {
|
|||||||
void AsyncWebSocketClient::_onDisconnect() {
|
void AsyncWebSocketClient::_onDisconnect() {
|
||||||
// Serial.println("onDis");
|
// Serial.println("onDis");
|
||||||
_client = nullptr;
|
_client = nullptr;
|
||||||
|
_server->_handleDisconnect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
|
void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
|
||||||
@@ -857,6 +822,16 @@ AsyncWebSocketClient *AsyncWebSocket::_newClient(AsyncWebServerRequest *request)
|
|||||||
return &_clients.back();
|
return &_clients.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AsyncWebSocket::_handleDisconnect(AsyncWebSocketClient *client) {
|
||||||
|
const auto client_id = client->id();
|
||||||
|
const auto iter = std::find_if(std::begin(_clients), std::end(_clients), [client_id](const AsyncWebSocketClient &c) {
|
||||||
|
return c.id() == client_id;
|
||||||
|
});
|
||||||
|
if (iter != std::end(_clients)) {
|
||||||
|
_clients.erase(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool AsyncWebSocket::availableForWriteAll() {
|
bool AsyncWebSocket::availableForWriteAll() {
|
||||||
return std::none_of(std::begin(_clients), std::end(_clients), [](const AsyncWebSocketClient &c) {
|
return std::none_of(std::begin(_clients), std::end(_clients), [](const AsyncWebSocketClient &c) {
|
||||||
return c.queueIsFull();
|
return c.queueIsFull();
|
||||||
@@ -1300,11 +1275,20 @@ AsyncWebSocketResponse::AsyncWebSocketResponse(const String &key, AsyncWebSocket
|
|||||||
}
|
}
|
||||||
k.concat(key);
|
k.concat(key);
|
||||||
k.concat(WS_STR_UUID);
|
k.concat(WS_STR_UUID);
|
||||||
|
#ifdef LIBRETINY
|
||||||
|
mbedtls_sha1_context ctx;
|
||||||
|
mbedtls_sha1_init(&ctx);
|
||||||
|
mbedtls_sha1_starts(&ctx);
|
||||||
|
mbedtls_sha1_update(&ctx, (const uint8_t *)k.c_str(), k.length());
|
||||||
|
mbedtls_sha1_finish(&ctx, hash);
|
||||||
|
mbedtls_sha1_free(&ctx);
|
||||||
|
#else
|
||||||
SHA1Builder sha1;
|
SHA1Builder sha1;
|
||||||
sha1.begin();
|
sha1.begin();
|
||||||
sha1.add((const uint8_t *)k.c_str(), k.length());
|
sha1.add((const uint8_t *)k.c_str(), k.length());
|
||||||
sha1.calculate();
|
sha1.calculate();
|
||||||
sha1.getBytes(hash);
|
sha1.getBytes(hash);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
base64_encodestate _state;
|
base64_encodestate _state;
|
||||||
base64_init_encodestate(&_state);
|
base64_init_encodestate(&_state);
|
||||||
|
@@ -5,8 +5,14 @@
|
|||||||
#define ASYNCWEBSOCKET_H_
|
#define ASYNCWEBSOCKET_H_
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
|
||||||
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
|
#ifdef LIBRETINY
|
||||||
|
#ifdef round
|
||||||
|
#undef round
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#ifndef WS_MAX_QUEUED_MESSAGES
|
#ifndef WS_MAX_QUEUED_MESSAGES
|
||||||
#define WS_MAX_QUEUED_MESSAGES 32
|
#define WS_MAX_QUEUED_MESSAGES 32
|
||||||
@@ -47,7 +53,62 @@ using AsyncWebSocketSharedBuffer = std::shared_ptr<std::vector<uint8_t>>;
|
|||||||
class AsyncWebSocket;
|
class AsyncWebSocket;
|
||||||
class AsyncWebSocketResponse;
|
class AsyncWebSocketResponse;
|
||||||
class AsyncWebSocketClient;
|
class AsyncWebSocketClient;
|
||||||
class AsyncWebSocketControl;
|
|
||||||
|
/*
|
||||||
|
* Control Frame
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AsyncWebSocketControl {
|
||||||
|
private:
|
||||||
|
uint8_t _opcode;
|
||||||
|
uint8_t *_data;
|
||||||
|
size_t _len;
|
||||||
|
bool _mask;
|
||||||
|
bool _finished;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebSocketControl(uint8_t opcode, const uint8_t *data = NULL, size_t len = 0, bool mask = false)
|
||||||
|
: _opcode(opcode), _len(len), _mask(len && mask), _finished(false) {
|
||||||
|
if (data == NULL) {
|
||||||
|
_len = 0;
|
||||||
|
}
|
||||||
|
if (_len) {
|
||||||
|
if (_len > 125) {
|
||||||
|
_len = 125;
|
||||||
|
}
|
||||||
|
|
||||||
|
_data = (uint8_t *)malloc(_len);
|
||||||
|
|
||||||
|
if (_data == NULL) {
|
||||||
|
#ifdef ESP32
|
||||||
|
log_e("Failed to allocate");
|
||||||
|
#endif
|
||||||
|
_len = 0;
|
||||||
|
} else {
|
||||||
|
memcpy(_data, data, len);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncWebSocketControl() {
|
||||||
|
if (_data != NULL) {
|
||||||
|
free(_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool finished() const {
|
||||||
|
return _finished;
|
||||||
|
}
|
||||||
|
uint8_t opcode() {
|
||||||
|
return _opcode;
|
||||||
|
}
|
||||||
|
uint8_t len() {
|
||||||
|
return _len + 2;
|
||||||
|
}
|
||||||
|
size_t send(AsyncClient *client);
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/** Message type as defined by enum AwsFrameType.
|
/** Message type as defined by enum AwsFrameType.
|
||||||
@@ -152,7 +213,7 @@ private:
|
|||||||
uint32_t _clientId;
|
uint32_t _clientId;
|
||||||
AwsClientStatus _status;
|
AwsClientStatus _status;
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
mutable std::mutex _lock;
|
mutable std::recursive_mutex _lock;
|
||||||
#endif
|
#endif
|
||||||
std::deque<AsyncWebSocketControl> _controlQueue;
|
std::deque<AsyncWebSocketControl> _controlQueue;
|
||||||
std::deque<AsyncWebSocketMessage> _messageQueue;
|
std::deque<AsyncWebSocketMessage> _messageQueue;
|
||||||
@@ -385,6 +446,7 @@ public:
|
|||||||
return _cNextId++;
|
return _cNextId++;
|
||||||
}
|
}
|
||||||
AsyncWebSocketClient *_newClient(AsyncWebServerRequest *request);
|
AsyncWebSocketClient *_newClient(AsyncWebServerRequest *request);
|
||||||
|
void _handleDisconnect(AsyncWebSocketClient *client);
|
||||||
void _handleEvent(AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len);
|
void _handleEvent(AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len);
|
||||||
bool canHandle(AsyncWebServerRequest *request) const override final;
|
bool canHandle(AsyncWebServerRequest *request) const override final;
|
||||||
void handleRequest(AsyncWebServerRequest *request) override final;
|
void handleRequest(AsyncWebServerRequest *request) override final;
|
||||||
|
@@ -15,16 +15,13 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef ESP32
|
#if defined(ESP32) || defined(LIBRETINY)
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESPAsyncTCP.h>
|
#include <ESPAsyncTCP.h>
|
||||||
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
|
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
|
||||||
#include <RPAsyncTCP.h>
|
#include <RPAsyncTCP.h>
|
||||||
#include <HTTP_Method.h>
|
#include <HTTP_Method.h>
|
||||||
#include <WiFi.h>
|
|
||||||
#include <http_parser.h>
|
#include <http_parser.h>
|
||||||
#else
|
#else
|
||||||
#error Platform not supported
|
#error Platform not supported
|
||||||
@@ -138,12 +135,20 @@ private:
|
|||||||
String _value;
|
String _value;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
AsyncWebHeader() {}
|
||||||
AsyncWebHeader(const AsyncWebHeader &) = default;
|
AsyncWebHeader(const AsyncWebHeader &) = default;
|
||||||
|
AsyncWebHeader(AsyncWebHeader &&) = default;
|
||||||
AsyncWebHeader(const char *name, const char *value) : _name(name), _value(value) {}
|
AsyncWebHeader(const char *name, const char *value) : _name(name), _value(value) {}
|
||||||
AsyncWebHeader(const String &name, const String &value) : _name(name), _value(value) {}
|
AsyncWebHeader(const String &name, const String &value) : _name(name), _value(value) {}
|
||||||
AsyncWebHeader(const String &data);
|
|
||||||
|
#ifndef ESP8266
|
||||||
|
[[deprecated("Use AsyncWebHeader::parse(data) instead")]]
|
||||||
|
#endif
|
||||||
|
AsyncWebHeader(const String &data)
|
||||||
|
: AsyncWebHeader(parse(data)){};
|
||||||
|
|
||||||
AsyncWebHeader &operator=(const AsyncWebHeader &) = default;
|
AsyncWebHeader &operator=(const AsyncWebHeader &) = default;
|
||||||
|
AsyncWebHeader &operator=(AsyncWebHeader &&other) = default;
|
||||||
|
|
||||||
const String &name() const {
|
const String &name() const {
|
||||||
return _name;
|
return _name;
|
||||||
@@ -151,7 +156,18 @@ public:
|
|||||||
const String &value() const {
|
const String &value() const {
|
||||||
return _value;
|
return _value;
|
||||||
}
|
}
|
||||||
|
|
||||||
String toString() const;
|
String toString() const;
|
||||||
|
|
||||||
|
// returns true if the header is valid
|
||||||
|
operator bool() const {
|
||||||
|
return _name.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const AsyncWebHeader parse(const String &data) {
|
||||||
|
return parse(data.c_str());
|
||||||
|
}
|
||||||
|
static const AsyncWebHeader parse(const char *data);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -187,6 +203,7 @@ class AsyncWebServerRequest {
|
|||||||
using FS = fs::FS;
|
using FS = fs::FS;
|
||||||
friend class AsyncWebServer;
|
friend class AsyncWebServer;
|
||||||
friend class AsyncCallbackWebHandler;
|
friend class AsyncCallbackWebHandler;
|
||||||
|
friend class AsyncFileResponse;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AsyncClient *_client;
|
AsyncClient *_client;
|
||||||
@@ -258,6 +275,8 @@ private:
|
|||||||
void _send();
|
void _send();
|
||||||
void _runMiddlewareChain();
|
void _runMiddlewareChain();
|
||||||
|
|
||||||
|
static void _getEtag(uint8_t trailer[4], char *serverETag);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
File _tempFile;
|
File _tempFile;
|
||||||
void *_tempObject;
|
void *_tempObject;
|
||||||
@@ -370,13 +389,7 @@ public:
|
|||||||
send(beginResponse(code, contentType, content, len, callback));
|
send(beginResponse(code, contentType, content, len, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
void send(FS &fs, const String &path, const char *contentType = asyncsrv::empty, bool download = false, AwsTemplateProcessor callback = nullptr) {
|
void send(FS &fs, const String &path, const char *contentType = asyncsrv::empty, bool download = false, AwsTemplateProcessor callback = nullptr);
|
||||||
if (fs.exists(path) || (!download && fs.exists(path + asyncsrv::T__gz))) {
|
|
||||||
send(beginResponse(fs, path, contentType, download, callback));
|
|
||||||
} else {
|
|
||||||
send(404);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void send(FS &fs, const String &path, const String &contentType, bool download = false, AwsTemplateProcessor callback = nullptr) {
|
void send(FS &fs, const String &path, const String &contentType, bool download = false, AwsTemplateProcessor callback = nullptr) {
|
||||||
send(fs, path, contentType.c_str(), download, callback);
|
send(fs, path, contentType.c_str(), download, callback);
|
||||||
}
|
}
|
||||||
@@ -1041,6 +1054,10 @@ public:
|
|||||||
setContentType(type.c_str());
|
setContentType(type.c_str());
|
||||||
}
|
}
|
||||||
void setContentType(const char *type);
|
void setContentType(const char *type);
|
||||||
|
bool addHeader(AsyncWebHeader &&header, bool replaceExisting = true);
|
||||||
|
bool addHeader(const AsyncWebHeader &header, bool replaceExisting = true) {
|
||||||
|
return header && addHeader(header.name(), header.value(), replaceExisting);
|
||||||
|
}
|
||||||
bool addHeader(const char *name, const char *value, bool replaceExisting = true);
|
bool addHeader(const char *name, const char *value, bool replaceExisting = true);
|
||||||
bool addHeader(const String &name, const String &value, bool replaceExisting = true) {
|
bool addHeader(const String &name, const String &value, bool replaceExisting = true) {
|
||||||
return addHeader(name.c_str(), value.c_str(), replaceExisting);
|
return addHeader(name.c_str(), value.c_str(), replaceExisting);
|
||||||
|
@@ -172,7 +172,11 @@ void AsyncLoggingMiddleware::run(AsyncWebServerRequest *request, ArMiddlewareNex
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_out->print(F("* Connection from "));
|
_out->print(F("* Connection from "));
|
||||||
|
#ifndef LIBRETINY
|
||||||
_out->print(request->client()->remoteIP().toString());
|
_out->print(request->client()->remoteIP().toString());
|
||||||
|
#else
|
||||||
|
_out->print(request->client()->remoteIP());
|
||||||
|
#endif
|
||||||
_out->print(':');
|
_out->print(':');
|
||||||
_out->println(request->client()->remotePort());
|
_out->println(request->client()->remotePort());
|
||||||
_out->print('>');
|
_out->print('>');
|
||||||
|
@@ -209,11 +209,14 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) {
|
|||||||
char buf[len];
|
char buf[len];
|
||||||
char *ret = lltoa(lw ^ request->_tempFile.size(), buf, len, 10);
|
char *ret = lltoa(lw ^ request->_tempFile.size(), buf, len, 10);
|
||||||
etag = ret ? String(ret) : String(request->_tempFile.size());
|
etag = ret ? String(ret) : String(request->_tempFile.size());
|
||||||
|
#elif defined(LIBRETINY)
|
||||||
|
long val = lw ^ request->_tempFile.size();
|
||||||
|
etag = String(val);
|
||||||
#else
|
#else
|
||||||
etag = lw ^ request->_tempFile.size(); // etag combines file size and lastmod timestamp
|
etag = lw ^ request->_tempFile.size(); // etag combines file size and lastmod timestamp
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
|
#if defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350) || defined(LIBRETINY)
|
||||||
etag = String(request->_tempFile.size());
|
etag = String(request->_tempFile.size());
|
||||||
#else
|
#else
|
||||||
etag = request->_tempFile.size();
|
etag = request->_tempFile.size();
|
||||||
|
@@ -22,10 +22,10 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer *s, AsyncClient *c)
|
AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer *s, AsyncClient *c)
|
||||||
: _client(c), _server(s), _handler(NULL), _response(NULL), _temp(), _parseState(PARSE_REQ_START), _version(0), _method(HTTP_ANY), _url(), _host(),
|
: _client(c), _server(s), _handler(NULL), _response(NULL), _onDisconnectfn(NULL), _temp(), _parseState(PARSE_REQ_START), _version(0), _method(HTTP_ANY),
|
||||||
_contentType(), _boundary(), _authorization(), _reqconntype(RCT_HTTP), _authMethod(AsyncAuthType::AUTH_NONE), _isMultipart(false), _isPlainPost(false),
|
_url(), _host(), _contentType(), _boundary(), _authorization(), _reqconntype(RCT_HTTP), _authMethod(AsyncAuthType::AUTH_NONE), _isMultipart(false),
|
||||||
_expectingContinue(false), _contentLength(0), _parsedLength(0), _multiParseState(0), _boundaryPosition(0), _itemStartIndex(0), _itemSize(0), _itemName(),
|
_isPlainPost(false), _expectingContinue(false), _contentLength(0), _parsedLength(0), _multiParseState(0), _boundaryPosition(0), _itemStartIndex(0),
|
||||||
_itemFilename(), _itemType(), _itemValue(), _itemBuffer(0), _itemBufferIndex(0), _itemIsFile(false), _tempObject(NULL) {
|
_itemSize(0), _itemName(), _itemFilename(), _itemType(), _itemValue(), _itemBuffer(0), _itemBufferIndex(0), _itemIsFile(false), _tempObject(NULL) {
|
||||||
c->onError(
|
c->onError(
|
||||||
[](void *r, AsyncClient *c, int8_t error) {
|
[](void *r, AsyncClient *c, int8_t error) {
|
||||||
(void)c;
|
(void)c;
|
||||||
@@ -341,10 +341,10 @@ bool AsyncWebServerRequest::_parseReqHead() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncWebServerRequest::_parseReqHeader() {
|
bool AsyncWebServerRequest::_parseReqHeader() {
|
||||||
int index = _temp.indexOf(':');
|
AsyncWebHeader header = AsyncWebHeader::parse(_temp);
|
||||||
if (index) {
|
if (header) {
|
||||||
String name(_temp.substring(0, index));
|
const String &name = header.name();
|
||||||
String value(_temp.substring(index + 2));
|
const String &value = header.value();
|
||||||
if (name.equalsIgnoreCase(T_Host)) {
|
if (name.equalsIgnoreCase(T_Host)) {
|
||||||
_host = value;
|
_host = value;
|
||||||
} else if (name.equalsIgnoreCase(T_Content_Type)) {
|
} else if (name.equalsIgnoreCase(T_Content_Type)) {
|
||||||
@@ -392,9 +392,9 @@ bool AsyncWebServerRequest::_parseReqHeader() {
|
|||||||
_reqconntype = RCT_EVENT;
|
_reqconntype = RCT_EVENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_headers.emplace_back(name, value);
|
_headers.emplace_back(std::move(header));
|
||||||
}
|
}
|
||||||
#if defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
|
#if defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350) || defined(LIBRETINY)
|
||||||
// Ancient PRI core does not have String::clear() method 8-()
|
// Ancient PRI core does not have String::clear() method 8-()
|
||||||
_temp = emptyString;
|
_temp = emptyString;
|
||||||
#else
|
#else
|
||||||
@@ -419,7 +419,7 @@ void AsyncWebServerRequest::_parsePlainPostChar(uint8_t data) {
|
|||||||
_params.emplace_back(name, urlDecode(value), true);
|
_params.emplace_back(name, urlDecode(value), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
|
#if defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350) || defined(LIBRETINY)
|
||||||
// Ancient PRI core does not have String::clear() method 8-()
|
// Ancient PRI core does not have String::clear() method 8-()
|
||||||
_temp = emptyString;
|
_temp = emptyString;
|
||||||
#else
|
#else
|
||||||
|
@@ -75,7 +75,6 @@ class AsyncFileResponse : public AsyncAbstractResponse {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
File _content;
|
File _content;
|
||||||
String _path;
|
|
||||||
void _setContentTypeFromPath(const String &path);
|
void _setContentTypeFromPath(const String &path);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@@ -6,17 +6,6 @@
|
|||||||
|
|
||||||
using namespace asyncsrv;
|
using namespace asyncsrv;
|
||||||
|
|
||||||
// Since ESP8266 does not link memchr by default, here's its implementation.
|
|
||||||
void *memchr(void *ptr, int ch, size_t count) {
|
|
||||||
unsigned char *p = static_cast<unsigned char *>(ptr);
|
|
||||||
while (count--) {
|
|
||||||
if (*p++ == static_cast<unsigned char>(ch)) {
|
|
||||||
return --p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Abstract Response
|
* Abstract Response
|
||||||
*
|
*
|
||||||
@@ -134,6 +123,30 @@ bool AsyncWebServerResponse::headerMustBePresentOnce(const String &name) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AsyncWebServerResponse::addHeader(AsyncWebHeader &&header, bool replaceExisting) {
|
||||||
|
if (!header) {
|
||||||
|
return false; // invalid header
|
||||||
|
}
|
||||||
|
for (auto i = _headers.begin(); i != _headers.end(); ++i) {
|
||||||
|
if (i->name().equalsIgnoreCase(header.name())) {
|
||||||
|
// header already set
|
||||||
|
if (replaceExisting) {
|
||||||
|
// remove, break and add the new one
|
||||||
|
_headers.erase(i);
|
||||||
|
break;
|
||||||
|
} else if (headerMustBePresentOnce(i->name())) { // we can have only one header with that name
|
||||||
|
// do not update
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
break; // accept multiple headers with the same name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// header was not found found, or existing one was removed
|
||||||
|
_headers.emplace_back(std::move(header));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool AsyncWebServerResponse::addHeader(const char *name, const char *value, bool replaceExisting) {
|
bool AsyncWebServerResponse::addHeader(const char *name, const char *value, bool replaceExisting) {
|
||||||
for (auto i = _headers.begin(); i != _headers.end(); ++i) {
|
for (auto i = _headers.begin(); i != _headers.end(); ++i) {
|
||||||
if (i->name().equalsIgnoreCase(name)) {
|
if (i->name().equalsIgnoreCase(name)) {
|
||||||
@@ -595,6 +608,16 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t *data, size
|
|||||||
* File Response
|
* File Response
|
||||||
* */
|
* */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the content type based on the file path extension
|
||||||
|
*
|
||||||
|
* This method determines the appropriate MIME content type for a file based on its
|
||||||
|
* file extension. It supports both external content type functions (if available)
|
||||||
|
* and an internal mapping of common file extensions to their corresponding MIME types.
|
||||||
|
*
|
||||||
|
* @param path The file path string from which to extract the extension
|
||||||
|
* @note The method modifies the internal _contentType member variable
|
||||||
|
*/
|
||||||
void AsyncFileResponse::_setContentTypeFromPath(const String &path) {
|
void AsyncFileResponse::_setContentTypeFromPath(const String &path) {
|
||||||
#if HAVE_EXTERN_GET_Content_Type_FUNCTION
|
#if HAVE_EXTERN_GET_Content_Type_FUNCTION
|
||||||
#ifndef ESP8266
|
#ifndef ESP8266
|
||||||
@@ -604,90 +627,138 @@ void AsyncFileResponse::_setContentTypeFromPath(const String &path) {
|
|||||||
#endif
|
#endif
|
||||||
_contentType = getContentType(path);
|
_contentType = getContentType(path);
|
||||||
#else
|
#else
|
||||||
if (path.endsWith(T__html)) {
|
const char *cpath = path.c_str();
|
||||||
|
const char *dot = strrchr(cpath, '.');
|
||||||
|
|
||||||
|
if (!dot) {
|
||||||
|
_contentType = T_application_octet_stream;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(dot, T__html) == 0 || strcmp(dot, T__htm) == 0) {
|
||||||
_contentType = T_text_html;
|
_contentType = T_text_html;
|
||||||
} else if (path.endsWith(T__htm)) {
|
} else if (strcmp(dot, T__css) == 0) {
|
||||||
_contentType = T_text_html;
|
|
||||||
} else if (path.endsWith(T__css)) {
|
|
||||||
_contentType = T_text_css;
|
_contentType = T_text_css;
|
||||||
} else if (path.endsWith(T__json)) {
|
} else if (strcmp(dot, T__js) == 0) {
|
||||||
_contentType = T_application_json;
|
|
||||||
} else if (path.endsWith(T__js)) {
|
|
||||||
_contentType = T_application_javascript;
|
_contentType = T_application_javascript;
|
||||||
} else if (path.endsWith(T__png)) {
|
} else if (strcmp(dot, T__json) == 0) {
|
||||||
|
_contentType = T_application_json;
|
||||||
|
} else if (strcmp(dot, T__png) == 0) {
|
||||||
_contentType = T_image_png;
|
_contentType = T_image_png;
|
||||||
} else if (path.endsWith(T__gif)) {
|
} else if (strcmp(dot, T__ico) == 0) {
|
||||||
_contentType = T_image_gif;
|
|
||||||
} else if (path.endsWith(T__jpg)) {
|
|
||||||
_contentType = T_image_jpeg;
|
|
||||||
} else if (path.endsWith(T__ico)) {
|
|
||||||
_contentType = T_image_x_icon;
|
_contentType = T_image_x_icon;
|
||||||
} else if (path.endsWith(T__svg)) {
|
} else if (strcmp(dot, T__svg) == 0) {
|
||||||
_contentType = T_image_svg_xml;
|
_contentType = T_image_svg_xml;
|
||||||
} else if (path.endsWith(T__eot)) {
|
} else if (strcmp(dot, T__jpg) == 0) {
|
||||||
_contentType = T_font_eot;
|
_contentType = T_image_jpeg;
|
||||||
} else if (path.endsWith(T__woff)) {
|
} else if (strcmp(dot, T__webp) == 0) {
|
||||||
_contentType = T_font_woff;
|
_contentType = T_image_webp;
|
||||||
} else if (path.endsWith(T__woff2)) {
|
} else if (strcmp(dot, T__avif) == 0) {
|
||||||
|
_contentType = T_image_avif;
|
||||||
|
} else if (strcmp(dot, T__gif) == 0) {
|
||||||
|
_contentType = T_image_gif;
|
||||||
|
} else if (strcmp(dot, T__woff2) == 0) {
|
||||||
_contentType = T_font_woff2;
|
_contentType = T_font_woff2;
|
||||||
} else if (path.endsWith(T__ttf)) {
|
} else if (strcmp(dot, T__woff) == 0) {
|
||||||
|
_contentType = T_font_woff;
|
||||||
|
} else if (strcmp(dot, T__ttf) == 0) {
|
||||||
_contentType = T_font_ttf;
|
_contentType = T_font_ttf;
|
||||||
} else if (path.endsWith(T__xml)) {
|
} else if (strcmp(dot, T__xml) == 0) {
|
||||||
_contentType = T_text_xml;
|
_contentType = T_text_xml;
|
||||||
} else if (path.endsWith(T__pdf)) {
|
} else if (strcmp(dot, T__pdf) == 0) {
|
||||||
_contentType = T_application_pdf;
|
_contentType = T_application_pdf;
|
||||||
} else if (path.endsWith(T__zip)) {
|
} else if (strcmp(dot, T__mp4) == 0) {
|
||||||
_contentType = T_application_zip;
|
_contentType = T_video_mp4;
|
||||||
} else if (path.endsWith(T__gz)) {
|
} else if (strcmp(dot, T__opus) == 0) {
|
||||||
_contentType = T_application_x_gzip;
|
_contentType = T_audio_opus;
|
||||||
} else {
|
} else if (strcmp(dot, T__webm) == 0) {
|
||||||
|
_contentType = T_video_webm;
|
||||||
|
} else if (strcmp(dot, T__txt) == 0) {
|
||||||
_contentType = T_text_plain;
|
_contentType = T_text_plain;
|
||||||
|
} else {
|
||||||
|
_contentType = T_application_octet_stream;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor for AsyncFileResponse that handles file serving with compression support
|
||||||
|
*
|
||||||
|
* This constructor creates an AsyncFileResponse object that can serve files from a filesystem,
|
||||||
|
* with automatic fallback to gzip-compressed versions if the original file is not found.
|
||||||
|
* It also handles ETag generation for caching and supports both inline and download modes.
|
||||||
|
*
|
||||||
|
* @param fs Reference to the filesystem object used to open files
|
||||||
|
* @param path Path to the file to be served (without compression extension)
|
||||||
|
* @param contentType MIME type of the file content (empty string for auto-detection)
|
||||||
|
* @param download If true, file will be served as download attachment; if false, as inline content
|
||||||
|
* @param callback Template processor callback for dynamic content processing
|
||||||
|
*/
|
||||||
AsyncFileResponse::AsyncFileResponse(FS &fs, const String &path, const char *contentType, bool download, AwsTemplateProcessor callback)
|
AsyncFileResponse::AsyncFileResponse(FS &fs, const String &path, const char *contentType, bool download, AwsTemplateProcessor callback)
|
||||||
: AsyncAbstractResponse(callback) {
|
: AsyncAbstractResponse(callback) {
|
||||||
_code = 200;
|
|
||||||
_path = path;
|
|
||||||
|
|
||||||
if (!download && !fs.exists(_path) && fs.exists(_path + T__gz)) {
|
// Try to open the uncompressed version first
|
||||||
_path = _path + T__gz;
|
_content = fs.open(path, fs::FileOpenMode::read);
|
||||||
|
if (_content.available()) {
|
||||||
|
_contentLength = _content.size();
|
||||||
|
} else {
|
||||||
|
// Try to open the compressed version (.gz)
|
||||||
|
String gzPath;
|
||||||
|
uint16_t pathLen = path.length();
|
||||||
|
gzPath.reserve(pathLen + 3);
|
||||||
|
gzPath.concat(path);
|
||||||
|
gzPath.concat(asyncsrv::T__gz);
|
||||||
|
_content = fs.open(gzPath, fs::FileOpenMode::read);
|
||||||
|
_contentLength = _content.size();
|
||||||
|
|
||||||
|
if (_content.seek(_contentLength - 8)) {
|
||||||
addHeader(T_Content_Encoding, T_gzip, false);
|
addHeader(T_Content_Encoding, T_gzip, false);
|
||||||
_callback = nullptr; // Unable to process zipped templates
|
_callback = nullptr; // Unable to process zipped templates
|
||||||
_sendContentLength = true;
|
_sendContentLength = true;
|
||||||
_chunked = false;
|
_chunked = false;
|
||||||
|
|
||||||
|
// Add ETag and cache headers
|
||||||
|
uint8_t crcInTrailer[4];
|
||||||
|
_content.read(crcInTrailer, sizeof(crcInTrailer));
|
||||||
|
char serverETag[9];
|
||||||
|
AsyncWebServerRequest::_getEtag(crcInTrailer, serverETag);
|
||||||
|
addHeader(T_ETag, serverETag, true);
|
||||||
|
addHeader(T_Cache_Control, T_no_cache, true);
|
||||||
|
|
||||||
|
_content.seek(0);
|
||||||
|
} else {
|
||||||
|
// File is corrupted or invalid
|
||||||
|
_code = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_content = fs.open(_path, fs::FileOpenMode::read);
|
if (*contentType == '\0') {
|
||||||
_contentLength = _content.size();
|
|
||||||
|
|
||||||
if (strlen(contentType) == 0) {
|
|
||||||
_setContentTypeFromPath(path);
|
_setContentTypeFromPath(path);
|
||||||
} else {
|
} else {
|
||||||
_contentType = contentType;
|
_contentType = contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (download) {
|
||||||
|
// Extract filename from path and set as download attachment
|
||||||
int filenameStart = path.lastIndexOf('/') + 1;
|
int filenameStart = path.lastIndexOf('/') + 1;
|
||||||
char buf[26 + path.length() - filenameStart];
|
char buf[26 + path.length() - filenameStart];
|
||||||
char *filename = (char *)path.c_str() + filenameStart;
|
char *filename = (char *)path.c_str() + filenameStart;
|
||||||
|
snprintf(buf, sizeof(buf), T_attachment, filename);
|
||||||
if (download) {
|
|
||||||
// set filename and force download
|
|
||||||
snprintf_P(buf, sizeof(buf), PSTR("attachment; filename=\"%s\""), filename);
|
|
||||||
} else {
|
|
||||||
// set filename and force rendering
|
|
||||||
snprintf_P(buf, sizeof(buf), PSTR("inline"));
|
|
||||||
}
|
|
||||||
addHeader(T_Content_Disposition, buf, false);
|
addHeader(T_Content_Disposition, buf, false);
|
||||||
|
} else {
|
||||||
|
// Serve file inline (display in browser)
|
||||||
|
addHeader(T_Content_Disposition, T_inline, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_code = 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncFileResponse::AsyncFileResponse(File content, const String &path, const char *contentType, bool download, AwsTemplateProcessor callback)
|
AsyncFileResponse::AsyncFileResponse(File content, const String &path, const char *contentType, bool download, AwsTemplateProcessor callback)
|
||||||
: AsyncAbstractResponse(callback) {
|
: AsyncAbstractResponse(callback) {
|
||||||
_code = 200;
|
_code = 200;
|
||||||
_path = path;
|
|
||||||
|
|
||||||
if (!download && String(content.name()).endsWith(T__gz) && !path.endsWith(T__gz)) {
|
if (String(content.name()).endsWith(T__gz) && !path.endsWith(T__gz)) {
|
||||||
addHeader(T_Content_Encoding, T_gzip, false);
|
addHeader(T_Content_Encoding, T_gzip, false);
|
||||||
_callback = nullptr; // Unable to process gzipped templates
|
_callback = nullptr; // Unable to process gzipped templates
|
||||||
_sendContentLength = true;
|
_sendContentLength = true;
|
||||||
@@ -822,7 +893,7 @@ AsyncResponseStream::AsyncResponseStream(const char *contentType, size_t bufferS
|
|||||||
_contentType = contentType;
|
_contentType = contentType;
|
||||||
// internal buffer will be null on allocation failure
|
// internal buffer will be null on allocation failure
|
||||||
_content = std::unique_ptr<cbuf>(new cbuf(bufferSize));
|
_content = std::unique_ptr<cbuf>(new cbuf(bufferSize));
|
||||||
if (_content->size() != bufferSize) {
|
if (bufferSize && _content->size() < bufferSize) {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
log_e("Failed to allocate");
|
log_e("Failed to allocate");
|
||||||
#endif
|
#endif
|
||||||
@@ -840,6 +911,14 @@ size_t AsyncResponseStream::write(const uint8_t *data, size_t len) {
|
|||||||
if (len > _content->room()) {
|
if (len > _content->room()) {
|
||||||
size_t needed = len - _content->room();
|
size_t needed = len - _content->room();
|
||||||
_content->resizeAdd(needed);
|
_content->resizeAdd(needed);
|
||||||
|
// log a warning if allocation failed, but do not return: keep writing the bytes we can
|
||||||
|
// with _content->write: if len is more than the available size in the buffer, only
|
||||||
|
// the available size will be written
|
||||||
|
if (len > _content->room()) {
|
||||||
|
#ifdef ESP32
|
||||||
|
log_e("Failed to allocate");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
size_t written = _content->write((const char *)data, len);
|
size_t written = _content->write((const char *)data, len);
|
||||||
_contentLength += written;
|
_contentLength += written;
|
||||||
|
@@ -4,10 +4,18 @@
|
|||||||
#include "ESPAsyncWebServer.h"
|
#include "ESPAsyncWebServer.h"
|
||||||
#include "WebHandlerImpl.h"
|
#include "WebHandlerImpl.h"
|
||||||
|
|
||||||
|
#if defined(ESP32) || defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350) || defined(LIBRETINY)
|
||||||
|
#include <WiFi.h>
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#else
|
||||||
|
#error Platform not supported
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace asyncsrv;
|
using namespace asyncsrv;
|
||||||
|
|
||||||
bool ON_STA_FILTER(AsyncWebServerRequest *request) {
|
bool ON_STA_FILTER(AsyncWebServerRequest *request) {
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
return WiFi.localIP() == request->client()->localIP();
|
return WiFi.localIP() == request->client()->localIP();
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
@@ -15,7 +23,7 @@ bool ON_STA_FILTER(AsyncWebServerRequest *request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ON_AP_FILTER(AsyncWebServerRequest *request) {
|
bool ON_AP_FILTER(AsyncWebServerRequest *request) {
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI
|
||||||
return WiFi.localIP() != request->client()->localIP();
|
return WiFi.localIP() != request->client()->localIP();
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
|
142
src/literals.h
142
src/literals.h
@@ -10,39 +10,39 @@ static constexpr const char *empty = "";
|
|||||||
static constexpr const char *T__opaque = "\", opaque=\"";
|
static constexpr const char *T__opaque = "\", opaque=\"";
|
||||||
static constexpr const char *T_100_CONTINUE = "100-continue";
|
static constexpr const char *T_100_CONTINUE = "100-continue";
|
||||||
static constexpr const char *T_13 = "13";
|
static constexpr const char *T_13 = "13";
|
||||||
static constexpr const char *T_ACCEPT = "accept";
|
static constexpr const char *T_ACCEPT = "Accept";
|
||||||
static constexpr const char *T_Accept_Ranges = "accept-ranges";
|
static constexpr const char *T_Accept_Ranges = "Accept-Ranges";
|
||||||
static constexpr const char *T_app_xform_urlencoded = "application/x-www-form-urlencoded";
|
static constexpr const char *T_attachment = "attachment; filename=\"%s\"";
|
||||||
static constexpr const char *T_AUTH = "authorization";
|
static constexpr const char *T_AUTH = "Authorization";
|
||||||
static constexpr const char *T_auth_nonce = "\", qop=\"auth\", nonce=\"";
|
static constexpr const char *T_auth_nonce = "\", qop=\"auth\", nonce=\"";
|
||||||
static constexpr const char *T_BASIC = "basic";
|
static constexpr const char *T_BASIC = "Basic";
|
||||||
static constexpr const char *T_BASIC_REALM = "basic realm=\"";
|
static constexpr const char *T_BASIC_REALM = "Basic realm=\"";
|
||||||
static constexpr const char *T_BEARER = "bearer";
|
static constexpr const char *T_BEARER = "Bearer";
|
||||||
static constexpr const char *T_BODY = "body";
|
static constexpr const char *T_BODY = "body";
|
||||||
static constexpr const char *T_Cache_Control = "cache-control";
|
static constexpr const char *T_Cache_Control = "Cache-Control";
|
||||||
static constexpr const char *T_chunked = "chunked";
|
static constexpr const char *T_chunked = "chunked";
|
||||||
static constexpr const char *T_close = "close";
|
static constexpr const char *T_close = "close";
|
||||||
static constexpr const char *T_cnonce = "cnonce";
|
static constexpr const char *T_cnonce = "cnonce";
|
||||||
static constexpr const char *T_Connection = "connection";
|
static constexpr const char *T_Connection = "Connection";
|
||||||
static constexpr const char *T_Content_Disposition = "content-disposition";
|
static constexpr const char *T_Content_Disposition = "Content-Disposition";
|
||||||
static constexpr const char *T_Content_Encoding = "content-encoding";
|
static constexpr const char *T_Content_Encoding = "Content-Encoding";
|
||||||
static constexpr const char *T_Content_Length = "content-length";
|
static constexpr const char *T_Content_Length = "Content-Length";
|
||||||
static constexpr const char *T_Content_Type = "content-type";
|
static constexpr const char *T_Content_Type = "Content-Type";
|
||||||
static constexpr const char *T_Content_Location = "content-location";
|
static constexpr const char *T_Content_Location = "Content-Location";
|
||||||
static constexpr const char *T_Cookie = "cookie";
|
static constexpr const char *T_Cookie = "Cookie";
|
||||||
static constexpr const char *T_CORS_ACAC = "access-control-allow-credentials";
|
static constexpr const char *T_CORS_ACAC = "Access-Control-Allow-Credentials";
|
||||||
static constexpr const char *T_CORS_ACAH = "access-control-allow-headers";
|
static constexpr const char *T_CORS_ACAH = "Access-Control-Allow-Headers";
|
||||||
static constexpr const char *T_CORS_ACAM = "access-control-allow-methods";
|
static constexpr const char *T_CORS_ACAM = "Access-Control-Allow-Methods";
|
||||||
static constexpr const char *T_CORS_ACAO = "access-control-allow-origin";
|
static constexpr const char *T_CORS_ACAO = "Access-Control-Allow-Origin";
|
||||||
static constexpr const char *T_CORS_ACMA = "access-control-max-age";
|
static constexpr const char *T_CORS_ACMA = "Access-Control-Max-Age";
|
||||||
static constexpr const char *T_CORS_O = "origin";
|
static constexpr const char *T_CORS_O = "Origin";
|
||||||
static constexpr const char *T_data_ = "data: ";
|
static constexpr const char *T_data_ = "data: ";
|
||||||
static constexpr const char *T_Date = "date";
|
static constexpr const char *T_Date = "Date";
|
||||||
static constexpr const char *T_DIGEST = "digest";
|
static constexpr const char *T_DIGEST = "Digest";
|
||||||
static constexpr const char *T_DIGEST_ = "digest ";
|
static constexpr const char *T_DIGEST_ = "Digest ";
|
||||||
static constexpr const char *T_ETag = "etag";
|
static constexpr const char *T_ETag = "ETag";
|
||||||
static constexpr const char *T_event_ = "event: ";
|
static constexpr const char *T_event_ = "event: ";
|
||||||
static constexpr const char *T_EXPECT = "expect";
|
static constexpr const char *T_EXPECT = "Expect";
|
||||||
static constexpr const char *T_FALSE = "false";
|
static constexpr const char *T_FALSE = "false";
|
||||||
static constexpr const char *T_filename = "filename";
|
static constexpr const char *T_filename = "filename";
|
||||||
static constexpr const char *T_gzip = "gzip";
|
static constexpr const char *T_gzip = "gzip";
|
||||||
@@ -50,12 +50,13 @@ static constexpr const char *T_Host = "host";
|
|||||||
static constexpr const char *T_HTTP_1_0 = "HTTP/1.0";
|
static constexpr const char *T_HTTP_1_0 = "HTTP/1.0";
|
||||||
static constexpr const char *T_HTTP_100_CONT = "HTTP/1.1 100 Continue\r\n\r\n";
|
static constexpr const char *T_HTTP_100_CONT = "HTTP/1.1 100 Continue\r\n\r\n";
|
||||||
static constexpr const char *T_id__ = "id: ";
|
static constexpr const char *T_id__ = "id: ";
|
||||||
static constexpr const char *T_IMS = "if-modified-since";
|
static constexpr const char *T_IMS = "If-Modified-Since";
|
||||||
static constexpr const char *T_INM = "if-none-match";
|
static constexpr const char *T_INM = "If-None-Match";
|
||||||
|
static constexpr const char *T_inline = "inline";
|
||||||
static constexpr const char *T_keep_alive = "keep-alive";
|
static constexpr const char *T_keep_alive = "keep-alive";
|
||||||
static constexpr const char *T_Last_Event_ID = "last-event-id";
|
static constexpr const char *T_Last_Event_ID = "Last-Event-ID";
|
||||||
static constexpr const char *T_Last_Modified = "last-modified";
|
static constexpr const char *T_Last_Modified = "Last-Modified";
|
||||||
static constexpr const char *T_LOCATION = "location";
|
static constexpr const char *T_LOCATION = "Location";
|
||||||
static constexpr const char *T_LOGIN_REQ = "Login Required";
|
static constexpr const char *T_LOGIN_REQ = "Login Required";
|
||||||
static constexpr const char *T_MULTIPART_ = "multipart/";
|
static constexpr const char *T_MULTIPART_ = "multipart/";
|
||||||
static constexpr const char *T_name = "name";
|
static constexpr const char *T_name = "name";
|
||||||
@@ -69,21 +70,20 @@ static constexpr const char *T_realm = "realm";
|
|||||||
static constexpr const char *T_realm__ = "realm=\"";
|
static constexpr const char *T_realm__ = "realm=\"";
|
||||||
static constexpr const char *T_response = "response";
|
static constexpr const char *T_response = "response";
|
||||||
static constexpr const char *T_retry_ = "retry: ";
|
static constexpr const char *T_retry_ = "retry: ";
|
||||||
static constexpr const char *T_retry_after = "retry-after";
|
static constexpr const char *T_retry_after = "Retry-After";
|
||||||
static constexpr const char *T_nn = "\n\n";
|
static constexpr const char *T_nn = "\n\n";
|
||||||
static constexpr const char *T_rn = "\r\n";
|
static constexpr const char *T_rn = "\r\n";
|
||||||
static constexpr const char *T_rnrn = "\r\n\r\n";
|
static constexpr const char *T_rnrn = "\r\n\r\n";
|
||||||
static constexpr const char *T_Server = "server";
|
static constexpr const char *T_Server = "Server";
|
||||||
static constexpr const char *T_Transfer_Encoding = "transfer-encoding";
|
static constexpr const char *T_Transfer_Encoding = "Transfer-Encoding";
|
||||||
static constexpr const char *T_TRUE = "true";
|
static constexpr const char *T_TRUE = "true";
|
||||||
static constexpr const char *T_UPGRADE = "upgrade";
|
static constexpr const char *T_UPGRADE = "Upgrade";
|
||||||
static constexpr const char *T_uri = "uri";
|
static constexpr const char *T_uri = "uri";
|
||||||
static constexpr const char *T_username = "username";
|
static constexpr const char *T_username = "username";
|
||||||
static constexpr const char *T_WS = "websocket";
|
static constexpr const char *T_WS = "websocket";
|
||||||
static constexpr const char *T_WWW_AUTH = "www-authenticate";
|
static constexpr const char *T_WWW_AUTH = "WWW-Authenticate";
|
||||||
|
|
||||||
// HTTP Methods
|
// HTTP Methods
|
||||||
|
|
||||||
static constexpr const char *T_ANY = "ANY";
|
static constexpr const char *T_ANY = "ANY";
|
||||||
static constexpr const char *T_GET = "GET";
|
static constexpr const char *T_GET = "GET";
|
||||||
static constexpr const char *T_POST = "POST";
|
static constexpr const char *T_POST = "POST";
|
||||||
@@ -103,44 +103,55 @@ static constexpr const char *T_RCT_EVENT = "RCT_EVENT";
|
|||||||
static constexpr const char *T_ERROR = "ERROR";
|
static constexpr const char *T_ERROR = "ERROR";
|
||||||
|
|
||||||
// extensions & MIME-Types
|
// extensions & MIME-Types
|
||||||
static constexpr const char *T__css = ".css";
|
static constexpr const char *T__avif = ".avif"; // AVIF: Highly compressed images. Compatible with all modern browsers.
|
||||||
static constexpr const char *T__eot = ".eot";
|
static constexpr const char *T__csv = ".csv"; // CSV: Data logging and configuration
|
||||||
static constexpr const char *T__gif = ".gif";
|
static constexpr const char *T__css = ".css"; // CSS: Styling for web interfaces
|
||||||
static constexpr const char *T__gz = ".gz";
|
static constexpr const char *T__gif = ".gif"; // GIF: Simple animations. Legacy support
|
||||||
static constexpr const char *T__htm = ".htm";
|
static constexpr const char *T__gz = ".gz"; // GZ: compressed files
|
||||||
static constexpr const char *T__html = ".html";
|
static constexpr const char *T__htm = ".htm"; // HTM: Web interface files
|
||||||
static constexpr const char *T__ico = ".ico";
|
static constexpr const char *T__html = ".html"; // HTML: Web interface files
|
||||||
static constexpr const char *T__jpg = ".jpg";
|
static constexpr const char *T__ico = ".ico"; // ICO: Favicons, system icons. Legacy support
|
||||||
static constexpr const char *T__js = ".js";
|
static constexpr const char *T__jpg = ".jpg"; // JPEG/JPG: Photos. Legacy support
|
||||||
static constexpr const char *T__json = ".json";
|
static constexpr const char *T__js = ".js"; // JavaScript: Interactive functionality
|
||||||
static constexpr const char *T__pdf = ".pdf";
|
static constexpr const char *T__json = ".json"; // JSON: Data exchange format
|
||||||
static constexpr const char *T__png = ".png";
|
static constexpr const char *T__mp4 = ".mp4"; // MP4: Proprietary format. Worse compression than WEBM.
|
||||||
static constexpr const char *T__svg = ".svg";
|
static constexpr const char *T__opus = ".opus"; // OPUS: High compression audio format
|
||||||
static constexpr const char *T__ttf = ".ttf";
|
static constexpr const char *T__pdf = ".pdf"; // PDF: Universal document format
|
||||||
static constexpr const char *T__woff = ".woff";
|
static constexpr const char *T__png = ".png"; // PNG: Icons, logos, transparency. Legacy support
|
||||||
static constexpr const char *T__woff2 = ".woff2";
|
static constexpr const char *T__svg = ".svg"; // SVG: Vector graphics, icons (scalable, tiny file sizes)
|
||||||
static constexpr const char *T__xml = ".xml";
|
static constexpr const char *T__ttf = ".ttf"; // TTF: Font file. Legacy support
|
||||||
static constexpr const char *T__zip = ".zip";
|
static constexpr const char *T__txt = ".txt"; // TXT: Plain text files
|
||||||
static constexpr const char *T_application_javascript = "application/javascript";
|
static constexpr const char *T__webm = ".webm"; // WebM: Video. Open source, optimized for web. Compatible with all modern browsers.
|
||||||
|
static constexpr const char *T__webp = ".webp"; // WebP: Highly compressed images. Compatible with all modern browsers.
|
||||||
|
static constexpr const char *T__woff = ".woff"; // WOFF: Font file. Legacy support
|
||||||
|
static constexpr const char *T__woff2 = ".woff2"; // WOFF2: Better compression. Compatible with all modern browsers.
|
||||||
|
static constexpr const char *T__xml = ".xml"; // XML: Configuration and data files
|
||||||
|
static constexpr const char *T_application_javascript = "application/javascript"; // Obsolete type for JavaScript
|
||||||
static constexpr const char *T_application_json = "application/json";
|
static constexpr const char *T_application_json = "application/json";
|
||||||
static constexpr const char *T_application_msgpack = "application/msgpack";
|
static constexpr const char *T_application_msgpack = "application/msgpack";
|
||||||
|
static constexpr const char *T_application_octet_stream = "application/octet-stream";
|
||||||
static constexpr const char *T_application_pdf = "application/pdf";
|
static constexpr const char *T_application_pdf = "application/pdf";
|
||||||
static constexpr const char *T_application_x_gzip = "application/x-gzip";
|
static constexpr const char *T_app_xform_urlencoded = "application/x-www-form-urlencoded";
|
||||||
static constexpr const char *T_application_zip = "application/zip";
|
static constexpr const char *T_audio_opus = "audio/opus";
|
||||||
static constexpr const char *T_font_eot = "font/eot";
|
|
||||||
static constexpr const char *T_font_ttf = "font/ttf";
|
static constexpr const char *T_font_ttf = "font/ttf";
|
||||||
static constexpr const char *T_font_woff = "font/woff";
|
static constexpr const char *T_font_woff = "font/woff";
|
||||||
static constexpr const char *T_font_woff2 = "font/woff2";
|
static constexpr const char *T_font_woff2 = "font/woff2";
|
||||||
|
static constexpr const char *T_image_avif = "image/avif";
|
||||||
static constexpr const char *T_image_gif = "image/gif";
|
static constexpr const char *T_image_gif = "image/gif";
|
||||||
static constexpr const char *T_image_jpeg = "image/jpeg";
|
static constexpr const char *T_image_jpeg = "image/jpeg";
|
||||||
static constexpr const char *T_image_png = "image/png";
|
static constexpr const char *T_image_png = "image/png";
|
||||||
static constexpr const char *T_image_svg_xml = "image/svg+xml";
|
static constexpr const char *T_image_svg_xml = "image/svg+xml";
|
||||||
|
static constexpr const char *T_image_webp = "image/webp";
|
||||||
static constexpr const char *T_image_x_icon = "image/x-icon";
|
static constexpr const char *T_image_x_icon = "image/x-icon";
|
||||||
static constexpr const char *T_text_css = "text/css";
|
static constexpr const char *T_text_css = "text/css";
|
||||||
|
static constexpr const char *T_text_csv = "text/csv";
|
||||||
static constexpr const char *T_text_event_stream = "text/event-stream";
|
static constexpr const char *T_text_event_stream = "text/event-stream";
|
||||||
static constexpr const char *T_text_html = "text/html";
|
static constexpr const char *T_text_html = "text/html";
|
||||||
|
static constexpr const char *T_text_javascript = "text/javascript";
|
||||||
static constexpr const char *T_text_plain = "text/plain";
|
static constexpr const char *T_text_plain = "text/plain";
|
||||||
static constexpr const char *T_text_xml = "text/xml";
|
static constexpr const char *T_text_xml = "text/xml";
|
||||||
|
static constexpr const char *T_video_mp4 = "video/mp4";
|
||||||
|
static constexpr const char *T_video_webm = "video/webm";
|
||||||
|
|
||||||
// Response codes
|
// Response codes
|
||||||
static constexpr const char *T_HTTP_CODE_100 = "Continue";
|
static constexpr const char *T_HTTP_CODE_100 = "Continue";
|
||||||
@@ -175,7 +186,7 @@ static constexpr const char *T_HTTP_CODE_412 = "Precondition Failed";
|
|||||||
static constexpr const char *T_HTTP_CODE_413 = "Request Entity Too Large";
|
static constexpr const char *T_HTTP_CODE_413 = "Request Entity Too Large";
|
||||||
static constexpr const char *T_HTTP_CODE_414 = "Request-URI Too Large";
|
static constexpr const char *T_HTTP_CODE_414 = "Request-URI Too Large";
|
||||||
static constexpr const char *T_HTTP_CODE_415 = "Unsupported Media Type";
|
static constexpr const char *T_HTTP_CODE_415 = "Unsupported Media Type";
|
||||||
static constexpr const char *T_HTTP_CODE_416 = "Requested range not satisfiable";
|
static constexpr const char *T_HTTP_CODE_416 = "Requested Range Not Satisfiable";
|
||||||
static constexpr const char *T_HTTP_CODE_417 = "Expectation Failed";
|
static constexpr const char *T_HTTP_CODE_417 = "Expectation Failed";
|
||||||
static constexpr const char *T_HTTP_CODE_429 = "Too Many Requests";
|
static constexpr const char *T_HTTP_CODE_429 = "Too Many Requests";
|
||||||
static constexpr const char *T_HTTP_CODE_500 = "Internal Server Error";
|
static constexpr const char *T_HTTP_CODE_500 = "Internal Server Error";
|
||||||
@@ -183,11 +194,14 @@ static constexpr const char *T_HTTP_CODE_501 = "Not Implemented";
|
|||||||
static constexpr const char *T_HTTP_CODE_502 = "Bad Gateway";
|
static constexpr const char *T_HTTP_CODE_502 = "Bad Gateway";
|
||||||
static constexpr const char *T_HTTP_CODE_503 = "Service Unavailable";
|
static constexpr const char *T_HTTP_CODE_503 = "Service Unavailable";
|
||||||
static constexpr const char *T_HTTP_CODE_504 = "Gateway Time-out";
|
static constexpr const char *T_HTTP_CODE_504 = "Gateway Time-out";
|
||||||
static constexpr const char *T_HTTP_CODE_505 = "HTTP Version not supported";
|
static constexpr const char *T_HTTP_CODE_505 = "HTTP Version Not Supported";
|
||||||
static constexpr const char *T_HTTP_CODE_ANY = "Unknown code";
|
static constexpr const char *T_HTTP_CODE_ANY = "Unknown code";
|
||||||
|
|
||||||
static constexpr const uint8_t T_only_once_headers_len = 11;
|
static constexpr const char *T_only_once_headers[] = {
|
||||||
static constexpr const char *T_only_once_headers[] = {T_Content_Length, T_Content_Type, T_Date, T_ETag, T_Last_Modified, T_LOCATION, T_retry_after,
|
T_Accept_Ranges, T_Content_Length, T_Content_Type, T_Connection, T_CORS_ACAC, T_CORS_ACAH, T_CORS_ACAM, T_CORS_ACAO,
|
||||||
T_Transfer_Encoding, T_Content_Location, T_Server, T_WWW_AUTH};
|
T_CORS_ACMA, T_CORS_O, T_Date, T_DIGEST, T_ETag, T_Last_Modified, T_LOCATION, T_retry_after,
|
||||||
|
T_Transfer_Encoding, T_Content_Location, T_Server, T_WWW_AUTH
|
||||||
|
};
|
||||||
|
static constexpr size_t T_only_once_headers_len = sizeof(T_only_once_headers) / sizeof(T_only_once_headers[0]);
|
||||||
|
|
||||||
} // namespace asyncsrv
|
} // namespace asyncsrv
|
||||||
|
Reference in New Issue
Block a user