LWAN是高性能和可擴展的Web服務器。
該項目網站包含更多詳細信息。
| 作業系統 | 拱 | 發布 | 偵錯 | 靜態分析 | 測試 |
|---|---|---|---|---|---|
| Linux | x86_64 | 報告歷史記錄 | |||
| FreeBSD 14 | x86_64 | ||||
| OpenBSD 7.4 | x86_64 |
您可以自己構建LWAN,使用容器映像,也可以從您喜歡的發行版中獲取包裹。
在安裝LWAN之前,請確保安裝所有依賴關係。所有這些都是在任何GNU/Linux分佈中發現的常見依賴性;軟件包名稱會有所不同,但是使用您的發行版使用的任何軟件包管理工具搜索不難。
構建系統將尋找這些庫,並在可用的情況下啟用/鏈接。
-DENABLE_BROTLI=NO來禁用-DENABLE_ZSTD=NO來禁用-DENABLE_TLS=ON (默認)傳遞:-DUSE_ALTERNATIVE_MALLOC傳遞到以下值來使用替代內存分配器:pacman -S cmake zlibpkg install cmake pkgconfapt-get update && apt-get install git cmake zlib1g-dev pkg-configbrew install cmake pacman -S cmake zlib sqlite luajit mariadb-libs gperftools valgrind mbedtlspkg install cmake pkgconf sqlite3 lua51apt-get update && apt-get install git cmake zlib1g-dev pkg-config lua5.1-dev libsqlite3-dev libmariadb-dev libmbedtls-devbrew install cmake mariadb-connector-c sqlite [email protected] pkg-config ~$ git clone git://github.com/lpereira/lwan
~$ cd lwan
~/lwan$ mkdir build
~/lwan$ cd build
選擇發行版本(沒有調試符號,消息,啟用一些優化等):
~/lwan/build$ cmake .. -DCMAKE_BUILD_TYPE=Release
如果您想啟用優化但仍使用調試器,請改用此方法:
~/lwan/build$ cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
禁用優化並構建更具調試的版本:
~/lwan/build$ cmake .. -DCMAKE_BUILD_TYPE=Debug
~/lwan/build$ make
這將產生一些二進製文件:
src/bin/lwan/lwan :主LWAN可執行文件。可以使用--help來執行指導。src/bin/testrunner/testrunner :包含執行測試套件( src/scripts/testsuite.py )的代碼。src/samples/freegeoip/freegeoip :FreeGeoip樣本實現。需要sqlite。src/samples/techempower/techempower :Techempower Web框架基準的代碼。需要SQLite和Mariadb庫。src/samples/clock/clock :時鐘樣本。生成一個始終顯示本地時間的GIF文件。src/bin/tools/mimegen :構建擴展模仿類型表。在構建過程中使用。src/bin/tools/bin2hex :從二進製文件中生成一個C文件,適用於#include。在構建過程中使用。src/bin/tools/configdump :使用配置讀取器API轉移配置文件。用於測試。src/bin/tools/weighttp :重寫weighttp HTTP基準測試工具。src/bin/tools/statuslookupgen :為HTTP狀態代碼及其描述生成完美的哈希表。在構建過程中使用。 通過-DCMAKE_BUILD_TYPE=Release將啟用一些編譯器優化(例如LTO),並為當前體系結構調整代碼。
重要的
基準測試時,請使用發行版構建。默認值是調試構建,它不僅將所有請求記錄到標準輸出中,而且在握住鎖定的同時會嚴重按住服務器。
默認構建(即不通過-DCMAKE_BUILD_TYPE=Release )將構建一個適合調試目的的版本。此版本可以在Valgrind (如果存在標題)下使用,並包括在發行版中刪除的調試消息。每個請求都打印調試消息。
在這些構建中,可以啟用消毒劑。要選擇使用哪個使用LWAN的一個,請為CMAKE INVOCATION行指定以下選項之一:
-DSANITIZER=ubsan選擇未定義的行為消毒劑。-DSANITIZER=address選擇地址消毒劑。-DSANITIZER=thread選擇線程消毒劑。也可以選擇其他內存分配器。 Lwan目前支持TCMalloc,Mimalloc和Jemalloc開箱即用。要使用其中的任何一個,請使用“可選依賴項”部分中提供的名稱將-DALTERNATIVE_MALLOC=name傳遞給Cmake Invocation行。
-DUSE_SYSLOG=ON選件可以傳遞給CMake,除了標準輸出外,還可以登錄到系統日誌。
如果您要構建用於分發的LWAN,則使用-DMTUNE_NATIVE=OFF選項可能是明智的,否則生成的二進制可能無法在某些計算機上運行。
在有足夠新的標頭的Linux系統上安裝合適的MBEDTLS安裝的情況下,將自動啟用TLS支持,以支持KTLS,但可以通過傳遞-DENABLE_TLS=NO to Cmake禁用。
~/lwan/build$ make testsuite
這將在src/scripts/testsuite.py中編譯testrunner程序並執行回歸測試套件。
~/lwan/build$ make benchmark
這將編譯testrunner並執行基準腳本src/scripts/benchmark.py 。
LWAN也可以通過指定-DCMAKE_BUILD_TYPE=Coverage來構建覆蓋範圍構建類型。這使generate-coverage製造目標可以運行testrunner ,可以與LCOV一起準備測試覆蓋報告。
該存儲庫中的每個提交都會觸發該報告的產生,結果可公開可用。
通過編輯提供的lwan.conf來設置服務器;在下面的詳細信息中解釋了該格式。
筆記
LWAN將嘗試在當前目錄中找到基於可執行名稱的配置文件; testrunner.conf將用於testrunner二進制, lwan.conf用於lwan二進制,等等。
配置文件是從當前目錄加載的。如果未對此文件進行更改,則運行LWAN將服務於./wwwroot目錄中的靜態文件。 Lwan將在所有接口上的端口8080上收聽。
LWAN將檢測到CPU的數量,將增加開放文件描述符的最大數量,並通常會盡力為正在運行的環境自動設置合理的設置。這些設置中的許多可以在配置文件中進行調整,但是不要與它們混亂通常是個好主意。
提示
可選地, lwan二進製文件可用於無需任何配置文件的單發靜態文件服務。與--help一起運行 - 為此提供幫助。
LWAN使用熟悉的key = value配置文件語法。註釋由#字符(類似於Shell腳本,Python和Perl)支持。可以使用捲曲支架創建嵌套部分。部分可以是空的;在這種情況下,捲曲括號是可選的。
some_key_name等效於配置文件中的some key name (作為實現詳細信息,代碼讀取配置選項只能以下劃線為版本)。
提示
值可以包含環境變量。使用語法${VARIABLE_NAME} 。默認值可以用colon(例如${VARIABLE_NAME:foo}指定,如果設置為${VARIABLE_NAME} ,否則否則foo )。
sound volume = 11 # This one is 1 louder
playlist metal {
files = '''
/multi/line/strings/are/supported.mp3
/anything/inside/these/are/stored/verbatim.mp3
'''
}
playlist chiptune {
files = """
/if/it/starts/with/single/quotes/it/ends/with/single/quotes.mod
/but/it/can/use/double/quotes.s3m
"""
}
可以在lwan.conf和techempower.conf中找到一些示例。
可以通過在配置文件中的任何位置中在constants部分中指定常數在整個配置文件中定義和重複使用。僅在該部分定義特定常數之後才能使用常數。常數可以重新定義。如果未定義常數,則其值將從環境變量中獲得。如果在一個constants部分或環境中未定義它,則LWAN將使用適當的錯誤消息中止。
constants {
user_name = ${USER}
home_directory = ${HOME}
buffer_size = 1000000
}
上面指定的默認值的相同語法在此處有效(例如,如果${USER:nobody}未在環境變量中設置${user_name} user_name },則指定user_name為${USER}設置為nobody 。
| 類型 | 描述 |
|---|---|
str | 任何形式的自由形式文本,通常是特定應用程序的 |
int | 整數編號。範圍特定於應用程序 |
time | 時間間隔。請參閱下表的單位 |
bool | 布爾值。有關有效值,請參見下表 |
可以使用乘數指定時間字段。可以指定多個,它們只是添加在一起;例如,“ 1m 1W”指定“ 1個月和1週”(37天)。下表列出了所有已知乘數:
| 乘數 | 描述 |
|---|---|
s | 秒 |
m | 分鐘 |
h | 小時 |
d | 天 |
w | 7天星期 |
M | 30天 |
y | 365天 |
筆記
該表中沒有乘數的數字被忽略;讀取配置文件時會發出警告。數字及其乘數之間必須不存在空間。
| 真值 | 假值 |
|---|---|
| 與0不同的整數數字 | 0 |
on | off |
true | false |
yes | no |
通常,讓Lwan決定為您的環境決定最佳設置是一個好主意。但是,並非每個環境都是相同的,並且並非所有使用都可以自動確定,因此提供了一些配置選項。
| 選項 | 類型 | 預設 | 描述 |
|---|---|---|---|
keep_alive_timeout | time | 15 | 保持連接活力的超時 |
quiet | bool | false | 設置為TRUE,以不打印任何調試消息。僅有效釋放構建。 |
expires | time | 1M 1w | “到期”標頭的價值。默認值是1個月零1週 |
threads | int | 0 | I/O線程的數量。默認(0)是在線CPU的數量 |
proxy_protocol | bool | false | 啟用代理協議。支持版本1和2。僅在代理後面使用LWAN時才啟用此設置,並且代理支持此協議。否則,這允許任何人欺騙原點IP地址 |
max_post_data_size | int | 40960 | 設置發布請求的最大數據大小數量,字節 |
max_put_data_size | int | 40960 | 在字節中設置最大數據大小的數據大小數量 |
max_file_descriptors | int | 524288 | 最大文件描述符數。需要至少10倍threads |
request_buffer_size | int | 4096 | 請求緩衝尺寸長度。如果大於4096的默認值,則將動態分配。 |
allow_temp_files | str | "" | 使用臨時文件;設置post發布請求, put請求或all (等同於兩者都設置為post put )。 |
error_template | str | 默認錯誤模板 | 錯誤代碼的模板。請參閱下面的變量。 |
error_template的變量| 多變的 | 類型 | 描述 |
|---|---|---|
short_message | str | 簡短錯誤消息(例如Not found ) |
long_message | str | 長錯誤消息(例如, The requested resource could not be found on this server ) |
LWAN可以將其特權放在系統中的用戶中,並用Chroot限制其文件系統視圖。儘管沒有防彈性,但在這種情況下,這提供了第一層安全性。
為了使用此功能,請聲明straitjacket (或straightjacket )部分,然後設置一些選項。這要求將lwan作為root執行。
儘管可以在文件中的任何位置寫入此部分(只要是最高級別的聲明),但是,由於打開任何目錄,例如由於實例化了serve_files模塊,LWAN將拒絕啟動。 (此檢查僅在Linux上作為Malconfiguration的保障。)
提示
在site部分之前聲明一件緊身的夾克,以使配置文件和私人數據(例如TLS密鑰)在初始化後無法觸及的服務器。
| 選項 | 類型 | 預設 | 描述 |
|---|---|---|---|
user | str | NULL | 將特權放在此用戶名中 |
chroot | str | NULL | 通往chroot()的路徑 |
drop_capabilities | bool | true | 將所有功能(2)(在Linux下)或承諾(2)(在OpenBSD下)刪除所有功能。 |
如果需要為每個響應指定自定義標頭,則可以在全局範圍中聲明headers部分。本節看起來並不重要的順序。
例如,此聲明:
headers {
Server = Apache/1.0.0 or nginx/1.0.0 (at your option)
Some-Custom-Header = ${WITH_THIS_ENVIRONMENT_VARIABLE}
}
都將覆蓋Server標頭( Server: lwan ),並設置Some-Custom-Header並用$WITH_THIS_ENVIRONMENT_VARIABLE獲得的值設置。
某些標頭不能被覆蓋,因為在為其服務請求時發送其實際值時會引起問題。這些包括但不限於:
DateExpiresWWW-AuthenticateConnectionContent-TypeTransfer-EncodingAccess-Control-Allow-標題筆記
標題名稱也是對案例不敏感(和案例保存)的。覆蓋SeRVeR將覆蓋Server標頭,但按照配置文件的寫入方式發送。
每個LWAN過程僅支持兩個偵聽器:HTTP偵聽器( listener部分)和HTTPS偵聽器( tls_listener部分)。每種類型的聽眾只允許。
警告
TLS支持是實驗性的。儘管在初始測試期間穩定,但您的里程可能會有所不同。此時僅支持TLSV1.2,但計劃了TLSV1.3。
筆記
TLS支持需要嗎? Linux帶有tls.ko模塊內置或加載。將來可能會增加對其他操作系統的支持。 FreeBSD似乎是可能的,其他操作系統似乎沒有提供類似的功能。對於不支持的操作系統,使用TLS終端代理(例如Hitch)是一個不錯的選擇。
對於listener和tls_listener部分,唯一的參數是接口地址和要聆聽的端口。偵聽器語法為${ADDRESS}:${PORT} ,其中${ADDRESS}可以* (綁定到所有接口),IPv6地址(如果被Square Brackets包圍),IPv4地址或hostname。例如, listener localhost:9876只能在lo接口,端口9876中聆聽。
雖然listener部分不採用鍵,但tls_listener部分需要兩個: cert和key (每個指數分別指向磁盤上的位置,位於TLS證書和私有密鑰文件的位置),並採用可選的布爾hsts鍵,該密鑰控制是否在HTTPS響應上發送了Strict-Transport-Security標題。
提示
為了生成這些鍵用於測試目的,可以像以下內容一樣使用OpenSSL命令行工具: openssl req -nodes -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 7
筆記
建議在tls_listener部分之後立即聲明具有chroot選項的Straitjacket,以使證書和鑰匙的路徑從那時起就無法觸及。
如果使用SystemD插座激活,則可以將systemd指定為參數。 (如果指定了來自SystemD的多個偵聽器,則可以指定systemd:FileDescriptorName , FileDescriptorName遵循systemd.socket文檔中設置的約定。)
示例:
listener *:8080 # Listen on all interfaces, port 8080, HTTP
tls_listener *:8081 { # Listen on all interfaces, port 8081, HTTPS
cert = /path/to/cert.pem
key = /path/to/key.pem
}
# Use named systemd socket activation for HTTP listener
listener systemd:my-service-http.socket
# Use named systemd socket activation for HTTPS listener
tls_listener systemd:my-service-https.socket {
...
}
site部分將對給定URL前綴的請求做出響應的模塊和處理程序的實例。
為了路由URL,LWAN與請求URI最大的普通前綴與“偵聽器”部分中指定的一組前綴匹配。如何處理對特定前綴的請求取決於在偵聽器部分中聲明了哪個處理程序或模塊。處理程序和模塊在內部相似。處理程序僅僅是函數,沒有狀態,模塊持狀態(命名實例)。模塊的多個實例可以顯示在偵聽器部分中。
沒有特殊的語法將前綴連接到處理程序或模塊。所有配置解析器規則在此處應用。使用${NAME} ${PREFIX}將${PREFIX}鏈接到一個名為${NAME}的處理程序(如果${NAME}開始,則以&為&,如C的“ ofer of” ofer of ofers'oferator),或者是“運算符”的地址),或一個名為${NAME}的模塊。可以在此處使用空的部分。
每個模塊將具有其特定的選項集,並在下一節中列出。除了配置選項外,還可以在模塊實例的聲明中存在一個特殊的authorization部分。處理程序不採用任何配置選項,但可能包括authorization部分。
提示
使用--help命令行參數執行LWAN將顯示內置模塊和處理程序的列表。
以下是使用LWAN運送的模塊的一些基本文檔。
serve_files模塊將使用靜態文件,並自動創建目錄索引或提供預壓縮文件。根據某些啟發式方法,它通常會盡力以最快的方式提供文件。
| 選項 | 類型 | 預設 | 描述 |
|---|---|---|---|
path | str | NULL | 通往包含要提供文件的目錄的路徑 |
index_path | str | index.html | 文件名用作目錄的索引 |
serve_precompressed_path | bool | true | 如果存在$ file.gz,則比$ file更小且較新,並且客戶端接受gzip編碼,轉移它 |
auto_index | bool | true | 如果沒有index_path文件,則會自動生成目錄列表。否則,產量為404 |
auto_index_readme | bool | true | 作為自動生成目錄索引的一部分,包括讀書文件的內容 |
directory_list_template | str | NULL | 目錄列表的鬍鬚模板的路徑;默認情況下,使用內部模板 |
read_ahead | int | 131702 | 緩存打開文件時,最大的字節量要提前讀取。值為0禁用ReadAhead。 ReadAhead由低優先級線程執行,以在文件系統中讀取文件範圍時不會阻止I/O線程。 |
cache_for | time | 5s | 是時候將文件元數據(大小,壓縮內容,打開文件描述符等)保存在緩存中 |
筆記
在cache_for設置中指定的持續時間內,小於16KIB的文件將在RAM中被壓縮。 LWAN將始終嘗試使用Deflate壓縮,並選擇使用Brotli和ZSTD壓縮(如果在適當的支持下構建LWAN)。
如果壓縮不值得(例如,添加Content-Encoding標頭)會產生比發送未壓縮文件更大的響應,通常是很小的文件),LWAN不會花時間壓縮文件。
對於大於16KIB的文件,LWAN不會嘗試壓縮它們。在將來的版本中,它可能會執行此操作,並在壓縮文件時使用塊編碼(當然要達到一定限制),但就目前而言,僅考慮上表中的serve_precompressed_path th設置)。
在所有情況下,如果在文件系統中找到該版本,並且客戶端請求此編碼,則LWAN可能會嘗試使用GZZPICPECT版本。
directory_list_template的變量| 多變的 | 類型 | 描述 |
|---|---|---|
rel_path | str | 相對於根目錄真實路徑的路徑 |
readme | str | 找到的第一個讀數文件的內容( readme , readme.txt , read.me , README.TXT , README ) |
file_list | 迭代器 | 迭代文件列表 |
file_list.zebra_class | str | odd物品, even物品 |
file_list.icon | str | 通往文件類型圖標的路徑 |
file_list.name | str | 文件名(逃脫) |
file_list.type | str | 文件類型(目錄或常規文件) |
file_list.size | int | 文件大小 |
file_list.unit | str | file_size的單元 |
lua模塊將允許用LUA編程語言編寫的腳本來維修請求。儘管該模塊提供的功能非常斯巴達,但它能夠運行水手等框架。
可以從文件中提供腳本,也可以嵌入在配置文件中,並且加載它們的結果,標準LUA模塊,並且(如果使用Luajit)優化代碼的(如果使用Luajit)將被緩存一段時間。
| 選項 | 類型 | 預設 | 描述 |
|---|---|---|---|
default_type | str | text/plain | 用於響應的默認mime類型 |
script_file | str | NULL | LUA腳本的路徑 |
cache_period | time | 15s | 是時候將LUA狀態加載到內存中了 |
script | str | NULL | 內聯LUA腳本 |
筆記
LUA腳本無法使用全局變量,因為它們不僅可以由不同的線程提供服務,而且該狀態僅適用於cache_period配置選項中指定的時間。這是因為LWAN中的每個I/O線程都會創建一個LUA VM的實例(即每個I/O線程的一個lua_State struct),並且每個LWAN COROUTINE都會通過請求產生LUA線程(帶有lua_newthread() )。
每個端點都不需要一個LUA模塊的實例。嵌入在配置文件或其他方式中的單個腳本可以服務許多不同的端點。腳本應該具有以下簽名來實現函數: handle_${METHOD}_${ENDPOINT}(req) ,其中${METHOD}可以是http方法(即get , post ,post, head等),而${ENDPOINT}是由該功能處理所需的端點。如果特定版本不存在,將調用通用handle(req)函數。
提示
使用root端點進行catchall。例如,如果找不到該請求的其他處理程序,將調用處理程序函數handle_get_root() 。如果未指定CatchAll,則服務器將返回404 Not Found錯誤。
req參數指向一個包含從請求獲取信息或設置響應信息的方法,如下所示:
req:query_param(param)用密鑰param返回查詢參數(從查詢字符串),或者如果找不到的nilreq:post_param(param)返回post參數(僅適用於${POST}處理程序)帶有鍵param ,或者如果找不到的話, nilreq:set_response(str)設置對字符串str響應req:say(str)發送響應塊(使用http中的塊編碼)req:send_event(event, str)發送一個事件(使用服務器序列事件)req:cookie(param)返回名為param的cookie,或找不到nilreq:set_headers(tbl)從表tbl設置響應標頭;可以使用表值( {'foo'={'bar', 'baz'}} }中的表('foo'= {'baz'}})中,可以多次指定標題。必須在發送任何響應say()或send_event()之前要調用req:header(name)從請求中獲取標題,如果找不到的話, nilreq:sleep(ms)暫停了當前處理程序的指定數量的毫秒req:ws_upgrade()如果可以將連接升級到Websocket,則返回1 ; 0否則req:ws_write_text(str)通過WebSocket-updraded Connection發送str作為文本框架req:ws_write_binary(str)通過WebSocket-updraded Connection將str作為二進制幀發送req:ws_write(str)通過WebSocket-upgraded Connection發送str作為文本或二進制幀,具體取決於僅包含ASCII字符的內容req:ws_read()返回帶有最後一個Websocket框架內容的字符串,或一個指示狀態的數字(如果已斷開連接,則在linux上的enotConn/107;如果沒有任何可用的話,則在linux上eagain/11 eagain/eagain/noces in linomsg/nomsg/42 inlinux on Linux on Linux on Linux上否則否則)。以後的回報價值可能會改變一些更像Lua的東西。req:remote_address()返回帶有遠程IP地址的字符串。req:path()帶有請求路徑的字符串。req:query_string()返回帶有查詢字符串的字符串(如果沒有查詢字符串)。req:body()返回請求主體(發布/放置請求)。req:request_id()返回包含請求ID的字符串。req:request_date()返回日期響應標題中的Date 。req:is_https()如果通過https服務此請求,則返回true ,否則為false 。req:host()返回Host標頭(如果存在)的值,否則nil 。req:http_version()返回HTTP/1.0或HTTP/1.1具體取決於請求版本。req:http_method()用http方法(例如"GET" )返回大寫中的字符串。req:http_headers()返回一個帶有所有標題及其值的表。處理程序功能可以返回nil (在這種情況下,生成200 OK響應),也可以返回與HTTP狀態代碼匹配的數字。嘗試返回無效的HTTP狀態代碼或數字或nil以外的任何其他內容將導致500 Internal Server Error響應。
除了req參數中的MetAmethods外,還可以通過調用Lwan.log的方法來登錄具有不同日誌記錄級別的消息:
Lwan.log:warning(str)Lwan.log:info(str)Lwan.log:error(str)Lwan.log:critical(str) (也會謹慎使用lwan!Lwan.log:debug(str) (僅在調試構建中可用;否則否則) 筆記
如果LWAN是在Syslog支持的情況下構建的,則這些消息也將發送到系統日誌,否則將其打印為標準錯誤。
rewrite模塊將匹配URL中的模式,並給出重定向到另一個URL的選項,或以LWAN處理請求的方式重寫請求,就好像最初以這種方式製作了請求一樣。
筆記
從LUA 5.3.1分叉,常規的Expresion Engine可能不像大多數通用用途的發動機那樣包裝功能,而是專門選擇的,因為它是確定性的有限自動機,試圖使某種否認服務攻擊不可能。
可以使用簡單的文本替代語法指定新的URL,也可以使用LUA腳本。
提示
LUA腳本將包含LUA模塊提供的req METATOT中可用的相同的metAthods,因此它可以非常強大。
重寫模塊的每個實例都需要在匹配此類模式時執行pattern和操作。按照配置文件中出現的順序評估模式,並使用配置文件中的嵌套部分指定。例如,考慮以下示例,其中指定了兩種模式:
rewrite /some/base/endpoint {
pattern posts/(%d+) {
# Matches /some/base/endpointposts/2600 and /some/base/endpoint/posts/2600
rewrite_as = /cms/view-post?id=%1
}
pattern imgur/(%a+)/(%g+) {
# Matches /some/base/endpointimgur/gif/mpT94Ld and /some/base/endpoint/imgur/gif/mpT94Ld
redirect_to = https://i.imgur.com/%2.%1
}
}
該示例定義了兩種模式,一種提供了一個更漂亮的URL,該URL對用戶隱藏了,另一種提供了一種不同的方法來獲得直接鏈接,直接鏈接到流行的圖像託管服務上託管的圖像(即請求/some/base/endpoint/imgur/mp4/4kOZNYX將直接向IMGUR服務中的資源進行紅色指向)。
rewrite_as或redirect_to的值也可以是lua腳本;在這種情況下,必須將expand_with_lua設置為true ,而不是將簡單的文本替換語法用作上面的示例,而是必須定義一個名為handle_rewrite(req, captures)的函數。 req參數記錄在LUA模塊部分中; captures參數是包含所有捕獲的表(即captures[2]等於簡單的文本替代語法中的%2 )。此功能將新的URL返回重定向到。
該模塊本身沒有任何選擇。每個模式中都指定選項。
| 選項 | 類型 | 預設 | 描述 |
|---|---|---|---|
rewrite_as | str | NULL | 按照此模式重寫URL |
redirect_to | str | NULL | 重定向到新的URL遵循此模式 |
expand_with_lua | bool | false | 使用LUA腳本重定向或重寫請求 |
redirect_to和rewrite_as選項是相互排斥的,其中之一至少必須指定。
也可以指定條件以觸發重寫。要指定一個,打開condition塊,指定條件類型,然後將其參數用於評估該條件。只要每種條件有一個條件,就可以根據重寫規則設置多個條件:
| 狀態 | 可以使用替代。句法 | 要求的部分 | 參數 | 描述 |
|---|---|---|---|---|
cookie | 是的 | 是的 | 一個key = value | 檢查請求是否具有cookie key具有值value |
query | 是的 | 是的 | 一個key = value | 檢查是否請求有查詢變量key具有值value |
post | 是的 | 是的 | 一個key = value | 檢查請求是否有發布數據key具有值value |
header | 是的 | 是的 | 一個key = value | 檢查請求標頭key是否具有值value |
environment | 是的 | 是的 | 一個key = value | 檢查環境變量key是否具有值value |
stat | 是的 | 是的 | path , is_dir , is_file | 檢查文件系統中是否存在path ,並選擇檢查is_dir或is_file是否存在 |
encoding | 不 | 是的 | deflate , gzip , brotli , zstd , none | 檢查客戶端是否接受確定的編碼中的響應(例如deflate = yes用於Deflate編碼) |
proxied | 不 | 不 | 布爾 | 檢查請求是否已通過代理協議代理 |
http_1.0 | 不 | 不 | 布爾 | 檢查是否使用HTTP/1.0客戶端提出請求 |
is_https | 不 | 不 | 布爾 | 檢查是否通過https提出請求 |
has_query_string | 不 | 不 | 布爾 | 檢查請求是否具有查詢字符串(即使為空) |
method | 不 | 不 | 方法名稱 | 檢查HTTP方法是否是指定的方法 |
lua | 不 | 不 | 細繩 | 在字符串中運行LUA函數matches(req) ,並檢查它是否返回true或false |
backref | 不 | 是的 | 單個backref index = value | 檢查BackRef號碼是否匹配提供的值 |
可以使用替代。語法是指使用用於rewrite as或redirect to動作的相同替代語法引用匹配模式的能力。例如, condition cookie { some-cookie-name = foo-%1-bar }將替換%1與該條件相關的模式的第一匹匹配。
筆記
不需要部分的條件必須作為鑰匙寫;例如, condition has_query_string = yes 。
例如,如果一個人想發送site-dark-mode.css如果有一個帶有dark style cookie,並發送site-light-mode.css否則可以寫下:
pattern site.css {
rewrite as = /site-dark-mode.css
condition cookie { style = dark }
}
pattern site.css {
rewrite as = /site-light-mode.css
}
另一個示例:如果一個人想在文件系統中確實存在預壓縮文件,並且用戶請求它們:
pattern (%g+) {
condition encoding { brotli = yes }
condition stat { path = %1.brotli }
rewrite as = %1.brotli
}
pattern (%g+) {
condition encoding { gzip = yes }
condition stat { path = %1.gzip }
rewrite as = %1.gzip
}
pattern (%g+) {
condition encoding { zstd = yes }
condition stat { path = %1.zstd }
rewrite as = %1.zstd
}
pattern (%g+) {
condition encoding { deflate = yes }
condition stat { path = %1.deflate }
rewrite as = %1.deflate
}
筆記
通常,這不是必需的,因為文件服務模塊將自動執行此操作並選擇可用於所請求的編碼的最小文件,但這表明僅通過配置就可以具有類似的功能。
根據錫在錫中所說, redirect模塊將根據其配置中指定的選項301 Moved permanently (默認情況下;可以更改代碼,請參見下文)。通常,應使用rewrite模塊,因為它包含更多功能。但是,該模塊也用作如何編寫LWAN模塊(少於100行代碼)的示例。
如果未指定to選項”,則始終會生成500 Internal Server Error響應。指定無效的HTTP代碼或LWAN不知道的代碼(請參閱enum lwan_http_status ),將301 Moved Permanently 。
| 選項 | 類型 | 預設 | 描述 |
|---|---|---|---|
to | str | NULL | 重定向到 |
code | int | 301 | HTTP代碼執行重定向 |
response模塊將生成任何HTTP代碼的人為響應。除了作為如何編寫LWAN模塊的示例外,還可以用來從其他模塊中解釋空隙(例如,如果/與serve_files模塊一起使用/.git中的405 Not Allowed響應)。
如果所提供的code屬於LWAN已知的響應代碼,則將404 Not Found錯誤發送。
| 選項 | 類型 | 預設 | 描述 |
|---|---|---|---|
code | int | 999 | HTTP響應代碼 |
fastcgi模塊代理在連接到LWAN的HTTP客戶端與LWAN可訪問的FastCGI服務器之間的請求。例如,這很有用,可以使用腳本語言(例如PHP)的頁面。
筆記
這是該模塊的初步版本,因此,它沒有得到很好的優化,缺少某些功能,並且提供給環境的某些值是硬編碼的。
| 選項 | 類型 | 預設 | 描述 |
|---|---|---|---|
address | str | 連接的地址。可以是文件路徑(對於UNIX域插座),IPv4地址( aaa.bbb.ccc.ddd:port port )或IPv6地址( [...]:port )。 | |
script_path | str | CGI腳本所在的位置。 | |
default_index | str | index.php | 如果在請求URI中未指定的如果執行默認腳本。 |
可以在任何模塊實例或處理程序中聲明授權部分,並提供通過標準HTTP授權機制授權實現該請求的方法。為了要求授權訪問某個模塊實例或處理程序,請聲明具有basic參數的authorization部分,並設置其選項之一。
| 選項 | 類型 | 預設 | 描述 |
|---|---|---|---|
realm | str | Lwan | 授權領域。這通常在瀏覽器中的用戶/密碼UI中顯示 |
password_file | str | NULL | 包含用戶名和密碼的文件的路徑(用清晰的文本)。文件格式與LWAN使用的配置文件格式相同 |
警告
不僅將密碼存儲在服務器應訪問的文件中,還將它們保存在存儲器中幾秒鐘。如果可能的話,請避免使用此功能。
如果您打算向LWAN貢獻,請閱讀本節(並遵循)。這裡沒有任何意外。這主要遵循許多其他FOSS項目的規則和期望,但是每個人都期望事情有些不同。
Lwan試圖在整個項目中遵循一致的編碼樣式。如果您正在考慮為項目貢獻補丁,請嘗試匹配周圍代碼的樣式,尊重這種樣式。一般來說:
global_variables_are_named_like_this ,即使它們往往很少見,應該標記為static (少數例外)local_var , i , conntypedef很少在LWAN中使用#pragma once而不是通常的guard hackerylwan-private.hlwan_lwan_lwan_前綴的情況下命名/* Old C-style comments are preferred */clang-format可用於以可接受的方式格式化源代碼;提供.clang-format文件如果修改代碼的經過良好測試區域(例如事件循環,HTTP解析器等),請添加新的集成測試,並確保在發送拉動請求之前,所有測試(包括已發送的新測試)正在使用。可以通過修改src/scripts/testsuite.py添加測試,並通過直接從源根起調用該腳本或執行testsuite build構建目標來執行。
某些測試只能在Linux上使用,並且不會在其他平台上執行。
LWAN會自動通過OSS-Fuzz進行模糊測試。但是,要在本地進行模糊測試,可以按照說明進行本地測試。
當前,請求解析代碼,配置文件解析器,模板解析器以及重寫模塊中使用的LUA字符串模式匹配庫。
添加新的模糊是微不足道的:
src/bin/fuzz中。${FUZZER_NAME}_fuzzer.cc 。查看有關如何編寫這些信息的OSS模糊文檔和其他模糊器。src/fuzz/corpus中提供模糊語料庫。文件必須命名為corpus-${FUZZER_NAME}-${UNIQUE_ID} 。 ELF目標上liblwan的共享對象版本(例如Linux)將使用符號過濾腳本隱藏被認為是庫的私有符號。請編輯src/lib/liblwan.sym添加應導出到liblwan.so的新符號。
Lwan試圖維持盡可能平坦的來源歷史,沒有合併。這意味著在合併之前,應在當前主人的頂部重新撥出拉力請求;有時,這可以通過GitHub接口自動完成,有時他們需要一些手動工作來解決衝突。如果詢問時,貢獻者是否會解決這些衝突,這將不勝感激。
建議按每次分支請求將您的更改推向叉子,而不是推到master分支;原因在下面說明。
請確保使用您的名字正確配置GIT(無論是您的法定名稱還是暱稱,這並不重要,但是應該足以值得信賴您)和有效的電子郵件地址。即使與他們發送提交是可以的,也無需添加Signed-off-by線路。
如果在拉動請求中請求更改,則有兩個選擇:
它不是強制執行的,但建議創建較小的提交。 LWAN的提交方式幾乎是任意的,因此請查看犯罪歷史,以了解應該如何製作該部門。 GIT提供了大量命令來實現此結果:已經提到的交互式折扣, git add的-p選項和git commit --amend是很好的例子。
提交消息應具有一行的摘要(〜72個字符),然後是一個空行,然後是80個字符線的段落,解釋了更改。如果摘要足夠好,通常不需要解釋更改的段落。嘗試寫出好的提交消息。
LWAN已獲得GNU通用公共許可證,版本2或((可根據您的選擇),任何以後的版本)獲得許可。所以:
雖然Lwan最初是為Linux編寫的,但它也已移植到BSD系統。構建系統將檢測受支持的功能,並在適當的情況下構建支持庫功能。
例如,EPOLL已在Kqueue的頂部實現,僅針對受支持的系統實現了僅使用Linux的SYSCALL和GNU擴展。這篇博客文章介紹了詳細信息以及如何使用#include_next 。
它可以實現良好的性能,在Core i7筆記本電腦上提供約320000個請求/秒,用於無磁盤訪問的請求,並且無需管道。
當需要磁盤I/O時,對於最大16KIB的文件,它會產生約290000個請求/秒;對於較大的文件,這會降至185000/秒,這也不太破舊。
當然,這些結果與保持陽光的連接以及在同一台計算機上運行的HightTP(因此使用可用於WebServer本身的資源)。
這些數字在沒有靜止的情況下下降了6倍。
利比拉有一個IRC頻道( #lwan )。可以使用標準的IRC客戶端。
這是使用LWAN並在野外看到的第三方物品的不確定列表。如果您在媒體或學術界看到LWAN提到的,那麼它可能很小,請與作者聯繫!這將使她一天!
也提供了其他一些分銷渠道:
Dockerfile ,可從Docker註冊表獲得。Lwan也被用作基準:
在學術期刊中提到:
在雜誌中提到:
在書中提到:
一些談話提到了Lwan:
不是真正的第三方,而是可惜:
LWAN容器圖像可在ghcr.io/lpereira/lwan上找到。諸如Docker或Podman之類的容器運行時間可用於在容器中構建和運行LWAN。
容器映像用發行版本編號標記,因此可以拉出特定版本的LWAN。
# latest version
docker pull ghcr.io/lpereira/lwan:latest
# pull a specific version
docker pull ghcr.io/lpereira/lwan:v0.3
克隆存儲庫,並使用Containerfile (Dockerfile)構建具有所有可選依賴項的LWAN。
podman build -t lwan .
圖像期望在/wwwroot上找到靜態內容,因此可以安裝包含內容的捲。
docker run --rm -p 8080:8080 -v ./www:/wwwroot lwan
要帶上您自己的lwan.conf ,只需將其安裝在/lwan.conf 。
podman run --rm -p 8080:8080 -v ./lwan.conf:/lwan.conf lwan
Podman支持插座激活容器。此示例顯示瞭如何在Linux主機上使用插座激活和Podman運行LWAN。
要求:Podman版本4.5.0或更高版本。
sudo useradd test
sudo machinectl shell test@
podman build -t lwan ~/lwan
mkdir -p ~/.config/containers/systemd
mkdir -p ~/.config/systemd/user
listener systemd:my.socket
site {
serve_files / {
path = /web
}
}
[Socket]
ListenStream=8080
[Unit]
After=my.socket
Requires=my.socket
[Container]
Network=none
Image=localhost/lwan
Volume=/home/test/lwan.conf:/lwan.conf:Z
Volume=/home/test/web:/web:Z
:Z由於LWAN只需要通過插座激活的插座進行通信,因此可以使用Network=none 。請參閱文章如何使用套接字激活限制容器特權。 mkdir ~/web
echo hello > ~/web/file.txt
systemctl --user daemon-reload
systemctl --user start my.socket
$ curl localhost:8080/file.txt
hello
這些是野外關於Lwan的一些引號。它們沒有特定順序。貢獻表示感謝:
“ Lwan就像是經典的,根據意大利語的定義 - 作家Italo Calvino:您可以一次又一次閱讀” Antonio Piccolboni
“我讀了Lwan的源代碼。特別是,使用Coroutine的一部分非常令人印象深刻,這比一本好小說更有趣。謝謝您。” - @patagonia
“對於服務器端,我們使用的是可以處理100k+ reqs/s的LWAN。它應該是超強的,並且對我們來說很好。” - @fawadkhaliq
“瘋狂的C事物” - 邁克爾·斯普洛爾
“表現最好的人是新人Lwan” - Infoq
“我從來沒有機會感謝您為Lwan致敬。這激發了我的啟發,開發Zewo” - @paulofariarl
“讓我說lwan是一件美的事物。我很吸引閱讀純淨娛樂的源代碼,太好了。高五” - @kwilczynski
“瘋狂科學” - JWZ
“與Lwan一起工作!我還沒有仔細地看待那樣,但是到目前為止,我喜歡我所看到的。您肯定有正確的想法。” - @ThinkingFish
“ Lwan是一件藝術品。每次我閱讀它時,我幾乎總是很敬畏。” - @neurodrone
“對於第10輪,LWAN奪冠” - Techempower
“ jeez這太了不起了。端到一端,搖滾紮實的工程。 Kjeetgill
“我本人只是一個業餘時間C編碼器,很驚訝我可以遵循代碼。很好!” cntlzw
“所有人都令人印象深刻,甚至因為被寫入(Grokkable!)C。好工作。” tpaschalis
“ Lwan是一個完全失敗的” Dermetfan