{"id":26675618,"url":"https://github.com/linkdata/webserv","last_synced_at":"2026-02-24T12:00:46.859Z","repository":{"id":243815746,"uuid":"813486344","full_name":"linkdata/webserv","owner":"linkdata","description":"Thin web service library","archived":false,"fork":false,"pushed_at":"2026-02-19T13:34:44.000Z","size":115,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-19T13:42:37.670Z","etag":null,"topics":["go","golang","nodependencies","service","web"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/linkdata.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":"audit_bug_repro_test.go","citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-06-11T07:20:50.000Z","updated_at":"2026-02-19T13:34:48.000Z","dependencies_parsed_at":"2024-06-11T10:30:36.265Z","dependency_job_id":"dabfa053-5b28-490a-b7f8-3114fef4958c","html_url":"https://github.com/linkdata/webserv","commit_stats":null,"previous_names":["linkdata/webserv"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/linkdata/webserv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linkdata%2Fwebserv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linkdata%2Fwebserv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linkdata%2Fwebserv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linkdata%2Fwebserv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/linkdata","download_url":"https://codeload.github.com/linkdata/webserv/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linkdata%2Fwebserv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29781194,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-24T10:45:18.109Z","status":"ssl_error","status_checked_at":"2026-02-24T10:45:09.911Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","nodependencies","service","web"],"created_at":"2025-03-26T03:18:54.286Z","updated_at":"2026-02-24T12:00:46.853Z","avatar_url":"https://github.com/linkdata.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![build](https://github.com/linkdata/webserv/actions/workflows/go.yml/badge.svg)](https://github.com/linkdata/webserv/actions/workflows/go.yml)\n[![coverage](https://github.com/linkdata/webserv/blob/coverage/main/badge.svg)](https://html-preview.github.io/?url=https://github.com/linkdata/webserv/blob/coverage/main/report.html)\n[![goreport](https://goreportcard.com/badge/github.com/linkdata/webserv)](https://goreportcard.com/report/github.com/linkdata/webserv)\n[![Docs](https://godoc.org/github.com/linkdata/webserv?status.svg)](https://godoc.org/github.com/linkdata/webserv)\n\n# webserv\n\nThin web service library.\n\nGiven a listen address, certificate directory, user name and data directory:\n\n* If certificate directory is not blank, reads `fullchain.pem` and `privkey.pem` from it.\n* If the listen address does not specify a port, default port depends on initial user privileges and if we have a certificate.\n* Starts listening on the address and port.\n* If listening succeeds but a later setup step fails, `Listen()` still returns an error and closes the listener, but `cfg.ListenURL` may already have been populated.\n* If user name is given, switch to that user.\n* If data directory is given, create it if needed.\n* When serving, listen for SIGINT and SIGTERM and do a controlled shutdown.\n* Path values are treated as trusted config: certificate filenames and data-dir suffixes may use `..` and symlinks and can resolve outside their base directories.\n\n## Usage\n\n`go get github.com/linkdata/webserv`\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t\"log/slog\"\n\t\"net/http\"\n\t\"os\"\n\n\t\"github.com/linkdata/webserv\"\n)\n\nvar (\n\tflagAddress   = flag.String(\"address\", os.Getenv(\"WEBSERV_ADDRESS\"), \"serve HTTP requests on given [address][:port]\")\n\tflagCertDir   = flag.String(\"certdir\", os.Getenv(\"WEBSERV_CERTDIR\"), \"where to find fullchain.pem and privkey.pem\")\n\tflagUser      = flag.String(\"user\", envOrDefault(\"WEBSERV_USER\", \"www-data\"), \"switch to this user after startup (*nix only)\")\n\tflagDataDir   = flag.String(\"datadir\", envOrDefault(\"WEBSERV_DATADIR\", \"$HOME\"), \"where to store data files after startup\")\n\tflagListenURL = flag.String(\"listenurl\", os.Getenv(\"WEBSERV_LISTENURL\"), \"specify the external URL clients can reach us at\")\n)\n\nfunc envOrDefault(envvar, defval string) (s string) {\n\tif s = os.Getenv(envvar); s == \"\" {\n\t\ts = defval\n\t}\n\treturn\n}\n\nfunc main() {\n\tflag.Parse()\n\n\tcfg := webserv.Config{\n\t\tAddress:   *flagAddress,\n\t\tCertDir:   *flagCertDir,\n\t\tUser:      *flagUser,\n\t\tDataDir:   *flagDataDir,\n\t\tListenURL: *flagListenURL,\n\t\tLogger:    slog.Default(),\n\t}\n\n\thttp.DefaultServeMux.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\t_, _ = w.Write([]byte(\"\u003chtml\u003e\u003cbody\u003eHello world!\u003c/body\u003e\u003c/html\u003e\"))\n\t})\n\n\tl, err := cfg.Listen()\n\tif err == nil {\n\t\tif err = cfg.Serve(context.Background(), l, nil); err == nil {\n\t\t\treturn\n\t\t}\n\t}\n\tslog.Error(err.Error())\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinkdata%2Fwebserv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinkdata%2Fwebserv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinkdata%2Fwebserv/lists"}