سرور وب net/httpd
سرور وب با پروندهی پیکربندی: چند سایت روی یک درگاه، مسیرها، هدایتها، حافظهی نهان و پروندههای ایستا.
واردسازی net.httpd
این بسته چند وبسایت را از یک فرایند و یک مجموعه درگاه اجرا میکند؛ کاری که معمولاً به nginx جلوی برنامهها سپرده میشود. سایتها را در یک پروندهی پیکربندی توصیف میکنید، آن را بار میکنید و Run را صدا میزنید. فرمان salam serve --config=web.salam دقیقاً همین کار را میکند و --test پرونده را بدون راهاندازی چیزی بررسی میکند.
پیکربندی به همان قالب بلوکی بقیهی سلام نوشته میشود: یک تنظیم name = value است، بلوک با name: باز و با end بسته میشود، توضیحها با // شروع میشوند و هر تنظیم و مقدارش در یک خط میمانند. رشتهها میان دو نقلقولاند، یا میان پشتنقلقول وقتی بکاسلش دارند، مثل عبارت باقاعده. کلیدهای پیکربندی انگلیسیاند، درست مثل کلیدهای JSON.
server:
log: access = "/var/log/salam/access.log" end
site:
listen = 80
names = "example.com www.example.com"
root = "/srv/example/public"
index = "index.html"
error page = 404 "404.html"
location "/assets/": cache = 30d end
location "= /health": return = 200 "ok" end
location "/old/": redirect = "https://example.com$uri" code = 301 end
end
site:
names = "blog.example.com *.blog.example.com"
root = "/srv/blog"
end
end
دو سایت روی یک درگاه با سرآیند Host از هم جدا میشوند. نام دقیق بر نام عام *.example.com میچربد و درخواست برای نامی که هیچکس ننوشته به سایتی میرسد که default = true دارد، وگرنه به اولین سایت آن درگاه. سایتی که listen ندارد روی درگاه ۸۰ گوش میدهد؛ با listen = "127.0.0.1:8080" نشانی را هم تعیین میکنید.
داخل یک سایت، مسیر درخواست مثل nginx با بلوکهای location مقایسه میشود:
location "= /health": دقیقاً همین مسیر، و چیز دیگری امتحان نمیشود.location "/assets/": هر مسیری که با آن شروع شود؛ بلندترین پیشوند به خاطر سپرده میشود.location "^~ /static/": پیشوندی که جلوی امتحان عبارتهای باقاعده را هم میگیرد.location "~ \.php$"و"~* \.png$": عبارت باقاعده (دومی به بزرگی و کوچکی حروف توجه نمیکند)، بعد از پیشوندها و به ترتیب پرونده امتحان میشود؛ اولین مطابقت برنده است، وگرنه بلندترین پیشوند به کار میرود.
تنظیمهای یک سایت، و یک مسیر مگر جایی که نوشته شده:
| تنظیم | معنا |
|---|---|
listen = 80 (سایت) | درگاه، بهدلخواه همراه نشانی: listen = "0.0.0.0:8080". میشود آن را تکرار کرد. |
names = "a.com b.com" (سایت) | نام میزبانهای سایت؛ *.a.com هر زیردامنه را میگیرد. |
default = true (سایت) | این سایت به نامهایی پاسخ میدهد که هیچ سایتی ادعا نکرده. |
root = "/srv/site" | پوشهای که مسیر درخواست به آن چسبانده میشود. مسیری که root خودش را دارد جای root سایت را میگیرد. |
alias = "/srv/files" (مسیر پیشوندی) | پوشهای که جای پیشوند مطابق را میگیرد: با location "/dl/": alias = "/srv/files" end مسیر /dl/a.zip میشود /srv/files/a.zip. |
index = "index.html index.htm" | پروندههایی که برای یک پوشه به ترتیب امتحان میشوند. پیشفرض index.html است. |
return = 200 "ok" | بیدرنگ با یک وضعیت و متن اختیاری پاسخ میدهد. |
redirect = "https://$host$request_uri"، code = 301 | هدایت میکند. کد پیشفرض ۳۰۱ است. متغیرها: $host، $uri، $args، $request_uri و $scheme. در سطح سایت برای همهی درخواستها و پیش از هر مسیر اجرا میشود. |
cache = 30d | همراه پروندهها Cache-Control: public, max-age=... میفرستد. یکاها: s، m، h، d، w، y. |
header = "Name" "value" | یک سرآیند پاسخ اضافه میکند. سرآیندهای سایت روی همهی پاسخها میروند و سرآیندهای مسیر فقط روی پاسخهای همان مسیر. |
error page = 404 "404.html" | پروندهای نسبت به root که با همان وضعیت خطا فرستاده میشود. |
بلوک log: مقدار access = "path" میگیرد؛ مسیر میتواند "stdout" یا "stderr" هم باشد. هر خط زمان، میزبان، روش، مسیر و وضعیت را دارد.
چیزهایی که مردم اشتباه میکنند:
- پروندهها فقط از
rootسایت مطابق خوانده میشوند. مسیر اول پاکسازی میشود، پس..نمیتواند از آن بالا برود، و هر پرونده یا پوشهای که نامش با نقطه شروع شود، مثل.envیا.git، با ۴۰۴ پاسخ میگیرد..well-knownمجاز است. - هر پرونده با سرآیندهای
ETagوLast-Modifiedفرستاده میشود. درخواستی باIf-None-Matchمطابق یاIf-Modified-Sinceبهاندازهی کافی تازه ۳۰۴ بدون بدنه میگیرد، و یکRange: bytes=a-b(و همچنینa-و-n) با ۲۰۶ همان بخش را میگیرد؛ بازهی بیرون از پرونده ۴۱۶ میگیرد.If-Rangeبا ETag رعایت میشود. چند بازه در یک درخواست با کل پرونده پاسخ داده میشود. - برای پروندهها فقط GET و HEAD پاسخ داده میشود؛ هر چیز دیگر ۴۰۵ با سرآیند
Allowمیگیرد. - نامها و مقدارها هنگام بارکردن پرونده بررسی میشوند: تنظیم غلطنوشته، درگاه خارج از بازه، پوشهی ریشهی ناموجود، عبارت باقاعدهی نادرست یا دو سایت با یک نام روی یک درگاه با خط و ستونش گزارش میشود و نام نزدیک پیشنهاد میشود. از پروندهای که مشکل دارد چیزی راه نمیافتد.
listen = 443 tlsخوانده میشود اما فعلاً رد میشود؛ HTTPS در نسخهای بعدی میآید، تا آن زمان یک پایاندهندهی TLS جلوی آن بگذارید.- بسته برای هر فرایند یک پیکربندی بارشده نگه میدارد. بار دوم آن را عوض میکند، اما سروری که در حال اجراست همان سایتهایی را دارد که با آن شروع شد.
- همهی چیزهایی که ممکن است در پرونده غلط باشد با
CheckیاLoadTextپیدا میشود، نه در اولین درخواست.
بستههای مرتبط: net/http سرور زیرین است، net/router مسیرها را نگه میدارد و net/httpd/conf تجزیهگری است که پرونده را میخواند.
تابعها
تجزیه مدت ParseDuration
تابع تجزیه مدت(text: رشته): صحیح۶۴45، 10m یا 30d را میخواند و به ثانیه برمیگرداند، یا -۱ اگر معتبر نباشد. یکاها s، m، h، d، w و y (۳۶۵ روز) هستند؛ بدون یکا یعنی ثانیه.واردسازی شبکه.سرور وب
تابع ریشه:
سرچاپ سرور وب.تجزیه مدت("45")
سرچاپ سرور وب.تجزیه مدت("90s")
سرچاپ سرور وب.تجزیه مدت("10m")
سرچاپ سرور وب.تجزیه مدت("12h")
سرچاپ سرور وب.تجزیه مدت("30d")
سرچاپ سرور وب.تجزیه مدت("2w")
سرچاپ سرور وب.تجزیه مدت("1y")
سرچاپ سرور وب.تجزیه مدت("")
سرچاپ سرور وب.تجزیه مدت("abc")
سرچاپ سرور وب.تجزیه مدت("5x")
پایانبارگذاری متن پیکربندی LoadText
تابع بارگذاری متن پیکربندی(text: رشته، file: رشته): منطقیtrue برمیگرداند؛ وگرنه مشکلها برای ProblemAt میمانند و چیز دیگری عوض نمیشود.واردسازی ورودی خروجی
واردسازی سیستم عامل
واردسازی زمان
واردسازی رشته
واردسازی شبکه.اچ تی تی پی
واردسازی شبکه.سرور وب
تابع سرو():
سرور وب.اجرا()
پایان
تابع بگیر(میزبان: رشته، مسیر: رشته): اچ تی تی پی.پاسخ:
ج := اچ تی تی پی.انجام درخواست("GET"، "http://" + میزبان + ":19435" + مسیر، اچ تی تی پی.سرصفحه جدید()، ""، اچ تی تی پی.گزینه های درخواست {})
برگشت ج
پایان
تابع ریشه:
ریشه_پوشه := سیستم عامل.پوشه موقت() + "/salam_httpd_serve_fa"
سیستم عامل.حذف همه(ریشه_پوشه)
سیستم عامل.ساخت پوشه ها(ریشه_پوشه + "/shop")
سیستم عامل.ساخت پوشه ها(ریشه_پوشه + "/blog")
ورودی خروجی.نوشتن پرونده(ریشه_پوشه + "/shop/index.html"، "فروشگاه")
ورودی خروجی.نوشتن پرونده(ریشه_پوشه + "/blog/index.html"، "وبلاگ")
ورودی خروجی.نوشتن پرونده(ریشه_پوشه + "/blog/404.html"، "چنین نوشتهای نیست")
متن := `
server:
site:
listen = 19435
names = "localhost"
root = "@ROOT@/shop"
header = "X-Site" "shop"
location "= /health": return = 200 "ok" end
location "/old/": redirect = "http://$host/new$uri" code = 302 end
end
site:
listen = 19435
names = "127.0.0.1"
root = "@ROOT@/blog"
error page = 404 "404.html"
end
end
`
سرچاپ سرور وب.بارگذاری متن پیکربندی(رشته.جایگزینی(متن، "@ROOT@"، ریشه_پوشه)، "serve.salam")
ن := نخساز(سرو)
زمان.خواب(۳۰۰)
الف := بگیر("localhost"، "/")
سرچاپ الف.وضعیت، الف.بدنه، اچ تی تی پی.دریافت سرصفحه(الف، "x-site")
ب := بگیر("127.0.0.1"، "/")
سرچاپ ب.وضعیت، ب.بدنه
سرچاپ بگیر("localhost"، "/health").بدنه
پ := بگیر("localhost"، "/old/page")
سرچاپ پ.وضعیت، اچ تی تی پی.دریافت سرصفحه(پ، "location")
ت := بگیر("127.0.0.1"، "/missing")
سرچاپ ت.وضعیت، ت.بدنه
سرچاپ بگیر("localhost"، "/.git/config").وضعیت
سرور وب.توقف()
نخپیوند(ن)
سیستم عامل.حذف همه(ریشه_پوشه)
پایانسایت برای SiteFor
تابع سایت برای(host: رشته، port: صحیح): صحیحواردسازی شبکه.سرور وب
تابع ریشه:
متن := `
server:
site:
listen = 8080
names = "example.test *.example.test"
location "/assets/": cache = 30d end
location "= /health": return = 200 "ok" end
location "^~ /static/": cache = 1h end
location "~ \.php$": return = 403 "no" end
end
site:
listen = 8080
names = "other.test"
default = true
end
end
`
سرچاپ سرور وب.بارگذاری متن پیکربندی(متن، "match.salam")، سرور وب.شمار مشکل ها()
سرچاپ سرور وب.شمار سایت ها()، سرور وب.نام های سایت(۰)، سرور وب.نام های سایت(۱)
سرچاپ سرور وب.سایت برای("example.test"، ۸۰۸۰)، سرور وب.سایت برای("API.Example.Test:8080"، ۸۰۸۰)، سرور وب.سایت برای("other.test."، ۸۰۸۰)
سرچاپ سرور وب.سایت برای("unknown.test"، ۸۰۸۰)، سرور وب.سایت برای("example.test"، ۹۰۹۰)
سرچاپ سرور وب.الگوی مسیر(سرور وب.مسیر برای(۰، "/health"))
سرچاپ سرور وب.الگوی مسیر(سرور وب.مسیر برای(۰، "/assets/logo.png"))
سرچاپ سرور وب.الگوی مسیر(سرور وب.مسیر برای(۰، "/static/a.php"))
سرچاپ سرور وب.الگوی مسیر(سرور وب.مسیر برای(۰، "/x/index.php"))
سرچاپ سرور وب.مسیر برای(۰، "/plain")، سرور وب.مسیر برای(۱، "/anything")
پایانمسیر برای LocationFor
تابع مسیر برای(site: صحیح، path: رشته): صحیح^~، بعد اولین عبارت باقاعدهی مطابق و بعد بلندترین پیشوند.نمونهی این مورد همراه با موارد بالاتر آمده است: net-httpd-Match.salam
شمار سایت ها SiteCount
تابع شمار سایت ها(): صحیحنمونهی این مورد همراه با موارد بالاتر آمده است: net-httpd-Match.salam
نام های سایت SiteNames
تابع نام های سایت(site: صحیح): رشتهنمونهی این مورد همراه با موارد بالاتر آمده است: net-httpd-Match.salam
الگوی مسیر LocationPattern
تابع الگوی مسیر(loc: صحیح): رشته=، ^~ یا ~.نمونهی این مورد همراه با موارد بالاتر آمده است: net-httpd-Match.salam
شمار مشکل ها ProblemCount
تابع شمار مشکل ها(): صحیحواردسازی شبکه.سرور وب
تابع آزمون(متن: رشته):
درستبود := سرور وب.بارگذاری متن پیکربندی(متن، "bad.salam")
سرچاپ درستبود، سرور وب.شمار مشکل ها()
تکرار سرور وب.شمار مشکل ها() در ای:
سرچاپ سرور وب.مشکل شماره(ای)
پایان
پایان
تابع ریشه:
آزمون("server:\n sit:\n end\nend\n")
آزمون("server:\n site:\n listen = 70000\n end\nend\n")
آزمون("server:\n site:\n names = \"a.test\"\n root = \"/no/such/dir\"\n end\nend\n")
آزمون("server:\n site:\n names = \"a.test\"\n end\n site:\n names = \"a.test\"\n end\nend\n")
آزمون("server:\n site:\n listen = 443 tls\n end\nend\n")
آزمون("server:\n site:\n names = \"a.test\"\n location \"/x\": hedaer = \"A\" \"b\" end\n end\nend\n")
آزمون("server:\nend\n")
آزمون("server:\n site:\n names = \"a.test\"\n cache = soon\n end\nend\n")
آزمون("server:\n site:\n names = \"a.test\"\n location \"/x\": alias = \"/tmp\" end\n location \"~ x\": alias = \"/tmp\" end\n end\nend\n")
پایانمشکل شماره ProblemAt
تابع مشکل شماره(i: صحیح): رشتهfile:line:column: message، با شمارهگذاری از ۰.نمونهی این مورد همراه با موارد بالاتر آمده است: net-httpd-Problems.salam
بارگذاری پرونده LoadFile
تابع بارگذاری پرونده(path: رشته): منطقیLoadText بار میکند. پروندهای که خوانده نشود هم یک مشکل است.واردسازی سیستم عامل
واردسازی شبکه.سرور وب
تابع ریشه:
ناپایا مسیر := "web.salam"
آرگ := سیستم عامل.آرگومان ها()
اگر آرگ.طول() > ۱:
مسیر = آرگ[۱]
پایان
اگر سرور وب.بررسی(مسیر) != ۰:
برگشت ۱
پایان
اگر وارونه سرور وب.بارگذاری پرونده(مسیر):
برگشت ۲
پایان
کد := سرور وب.اجرا()
سرور وب.توقف()
برگشت کد
پایانبررسی Check
تابع بررسی(path: رشته): صحیحsalam serve --config=FILE --test میکند: مشکلها را در خروجی خطا چاپ میکند و ۱ برمیگرداند، یا یک خط خلاصه چاپ میکند و ۰ برمیگرداند.نمونهی این مورد همراه با موارد بالاتر آمده است: net-httpd-Run.salam
اجرا Run
تابع اجرا(): صحیحStop صدا زده شود. اگر پیکربندی معتبری بار نشده باشد، گزارش باز نشود یا نشانی بسته نشود، بیدرنگ ۲ برمیگرداند.نمونهی این مورد همراه با موارد بالاتر آمده است: net-httpd-Serve.salam
توقف Stop
تابع توقف()Run برگردد. اتصالهای پذیرفتهشده تخلیه نمیشوند.نمونهی این مورد همراه با موارد بالاتر آمده است: net-httpd-Serve.salam