{"id":27938923,"url":"https://github.com/xiyoo0812/lhttp","last_synced_at":"2026-05-18T09:36:46.929Z","repository":{"id":47631299,"uuid":"388758587","full_name":"xiyoo0812/lhttp","owner":"xiyoo0812","description":"一个提供给lua使用的http协议解析库。","archived":false,"fork":false,"pushed_at":"2023-02-17T12:52:02.000Z","size":39,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-07T16:34:07.977Z","etag":null,"topics":["http","lua","server"],"latest_commit_sha":null,"homepage":"","language":"C++","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/xiyoo0812.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-07-23T10:07:14.000Z","updated_at":"2022-08-05T06:47:32.000Z","dependencies_parsed_at":"2025-05-07T08:58:32.074Z","dependency_job_id":"cae6af14-a29f-4067-ba58-ffe69afcd7a8","html_url":"https://github.com/xiyoo0812/lhttp","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/xiyoo0812/lhttp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xiyoo0812%2Flhttp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xiyoo0812%2Flhttp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xiyoo0812%2Flhttp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xiyoo0812%2Flhttp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xiyoo0812","download_url":"https://codeload.github.com/xiyoo0812/lhttp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xiyoo0812%2Flhttp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33172780,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-18T09:27:30.708Z","status":"ssl_error","status_checked_at":"2026-05-18T09:27:28.300Z","response_time":71,"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":["http","lua","server"],"created_at":"2025-05-07T08:58:30.197Z","updated_at":"2026-05-18T09:36:46.900Z","avatar_url":"https://github.com/xiyoo0812.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lhttp\n一个提供给lua使用的http协议解析库。\n\n# 依赖\n- [lua](https://github.com/xiyoo0812/lua.git)5.3以上\n- [luakit](https://github.com/xiyoo0812/luakit.git)一个luabind库\n- 项目路径如下\u003cbr\u003e\n  |--proj \u003cbr\u003e\n  \u0026emsp;|--lua \u003cbr\u003e\n  \u0026emsp;|--lhttp \u003cbr\u003e\n  \u0026emsp;|--luakit\n\n# 注意事项\n- 本库只做http协议解析\n- 数据收发由调用方实现\n\n# 用法\n```lua\n--本示例使用了quanta引擎\n--https://github.com/xiyoo0812/quanta.git\n--http_server.lua\nlocal lhttp         = require(\"lhttp\")\nlocal ljson         = require(\"lcjson\")\nlocal Socket        = import(\"driver/socket.lua\")\n\nlocal type          = type\nlocal tostring      = tostring\nlocal getmetatable  = getmetatable\nlocal log_err       = logger.err\nlocal log_info      = logger.info\nlocal log_debug     = logger.debug\nlocal json_encode   = ljson.encode\nlocal tunpack       = table.unpack\nlocal signalquit    = signal.quit\nlocal saddr         = string_ext.addr\n\nlocal thread_mgr    = quanta.get(\"thread_mgr\")\n\nlocal HttpServer = class()\nlocal prop = property(HttpServer)\nprop:reader(\"listener\", nil)        --网络连接对象\nprop:reader(\"ip\", nil)              --http server地址\nprop:reader(\"port\", 8080)           --http server端口\nprop:reader(\"clients\", {})          --clients\nprop:reader(\"requests\", {})         --requests\nprop:reader(\"get_handlers\", {})     --get_handlers\nprop:reader(\"put_handlers\", {})     --put_handlers\nprop:reader(\"del_handlers\", {})     --del_handlers\nprop:reader(\"post_handlers\", {})    --post_handlers\n\nfunction HttpServer:__init(http_addr)\n    self:setup(http_addr)\nend\n\nfunction HttpServer:setup(http_addr)\n    self.ip, self.port = saddr(http_addr)\n    local socket = Socket(self)\n    if not socket:listen(self.ip, self.port) then\n        log_info(\"[HttpServer][setup] now listen %s failed\", http_addr)\n        signalquit(1)\n        return\n    end\n    log_info(\"[HttpServer][setup] listen(%s:%s) success!\", self.ip, self.port)\n    self.listener = socket\nend\n\nfunction HttpServer:on_socket_error(socket, token, err)\n    if socket == self.listener then\n        log_info(\"[HttpServer][on_socket_error] listener(%s:%s) close!\", self.ip, self.port)\n        self.listener = nil\n        return\n    end\n    log_debug(\"[HttpServer][on_socket_error] client(token:%s) close!\", token)\n    self.clients[token] = nil\n    self.requests[token] = nil\nend\n\nfunction HttpServer:on_socket_accept(socket, token)\n    log_debug(\"[HttpServer][on_socket_accept] client(token:%s) connected!\", token)\n    self.clients[token] = socket\nend\n\nfunction HttpServer:on_socket_recv(socket, token)\n    local request = self.requests[token]\n    if not request then\n        request = lhttp.create_request()\n        log_debug(\"[HttpServer][on_socket_accept] create_request(token:%s)!\", token)\n        self.requests[token] = request\n    end\n    local buf = socket:get_recvbuf()\n    if #buf == 0 or not request.parse(buf) then\n        log_err(\"[HttpServer][on_socket_recv] http request append failed, close client(token:%s)!\", token)\n        self:response(socket, 400, \"this http request parse error!\")\n        return\n    end\n    socket:pop(#buf)\n    thread_mgr:fork(function()\n        local method = request.method\n        local headers = request.get_headers()\n        if method == \"GET\" then\n            local querys = request.get_params()\n            return self:on_http_request(self.get_handlers, socket, request.url, querys, headers)\n        end\n        if method == \"POST\" then\n            return self:on_http_request(self.post_handlers, socket, request.url, request.body, headers)\n        end\n        if method == \"PUT\" then\n            return self:on_http_request(self.put_handlers, socket, request.url, request.body, headers)\n        end\n        if method == \"DELETE\" then\n            local querys = request.get_params()\n            return self:on_http_request(self.del_handlers, socket, request.url, querys, headers)\n        end\n    end)\nend\n\n--注册get回调\nfunction HttpServer:register_get(url, handler, target)\n    log_debug(\"[HttpServer][register_get] url: %s\", url)\n    self.get_handlers[url] = { handler, target }\nend\n\n--注册post回调\nfunction HttpServer:register_post(url, handler, target)\n    log_debug(\"[HttpServer][register_post] url: %s\", url)\n    self.post_handlers[url] = { handler, target }\nend\n\n--注册put回调\nfunction HttpServer:register_put(url, handler, target)\n    log_debug(\"[HttpServer][register_put] url: %s\", url)\n    self.put_handlers[url] = { handler, target }\nend\n\n--注册del回调\nfunction HttpServer:register_del(url, handler, target)\n    log_debug(\"[HttpServer][register_del] url: %s\", url)\n    self.del_handlers[url] = { handler, target }\nend\n\n--生成response\nfunction HttpServer:build_response(status, content, headers)\n    local response = lhttp.create_response()\n    response.status = status\n    response.content = content\n    for name, value in pairs(headers or {}) do\n        response.set_header(name, value)\n    end\n    return response\nend\n\n--http post 回调\nfunction HttpServer:on_http_request(handlers, socket, url, ...)\n    log_info(\"[HttpServer][on_http_request] request %s process!\", url)\n    local handler_info = handlers[url] or handlers[\"*\"]\n    if handler_info then\n        local handler, target = tunpack(handler_info)\n        if not target then\n            if type(handler) == \"function\" then\n                local ok, response = pcall(handler, url, ...)\n                if not ok then\n                    response = { code = 1, msg = response }\n                end\n                self:response(socket, 200, response)\n                return\n            end\n        else\n            if type(handler) == \"string\" then\n                handler = target[handler]\n            end\n            if type(handler) == \"function\" then\n                local ok, response = pcall(handler, target, url, ...)\n                if not ok then\n                    response = { code = 1, msg = response }\n                end\n                self:response(socket, 200, response)\n                return\n            end\n        end\n    end\n    log_err(\"[HttpServer][on_http_request] request %s hasn't process!\", url)\n    self:response(socket, 404, \"this http request hasn't process!\")\nend\n\nfunction HttpServer:response(socket, status, response)\n    local token = socket:get_token()\n    if not token then\n        return\n    end\n    self.requests[token] = nil\n    if getmetatable(response) then\n        socket:send(response.serialize())\n        socket:close()\n        return\n    end\n    local new_resp = lhttp.create_response()\n    if type(response) == \"table\" then\n        new_resp.set_header(\"Content-Type\", \"application/json\")\n        new_resp.content = json_encode(response)\n    else\n        new_resp.set_header(\"Content-Type\", \"text/plain\")\n        new_resp.content = (type(response) == \"string\") and response or tostring(response)\n    end\n    new_resp.status = status\n    socket:send(new_resp.serialize())\n    socket:close()\nend\n\nreturn HttpServer\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxiyoo0812%2Flhttp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxiyoo0812%2Flhttp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxiyoo0812%2Flhttp/lists"}