{"action":"closed","number":418,"pull_request":{"url":"https://api.github.com/repos/yesodweb/wai/pulls/418","id":41644687,"html_url":"https://github.com/yesodweb/wai/pull/418","diff_url":"https://github.com/yesodweb/wai/pull/418.diff","patch_url":"https://github.com/yesodweb/wai/pull/418.patch","issue_url":"https://api.github.com/repos/yesodweb/wai/issues/418","number":418,"state":"closed","locked":false,"title":"Configurable Slowloris size","user":{"login":"mfine","id":60851,"avatar_url":"https://avatars.githubusercontent.com/u/60851?v=3","gravatar_id":"","url":"https://api.github.com/users/mfine","html_url":"https://github.com/mfine","followers_url":"https://api.github.com/users/mfine/followers","following_url":"https://api.github.com/users/mfine/following{/other_user}","gists_url":"https://api.github.com/users/mfine/gists{/gist_id}","starred_url":"https://api.github.com/users/mfine/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mfine/subscriptions","organizations_url":"https://api.github.com/users/mfine/orgs","repos_url":"https://api.github.com/users/mfine/repos","events_url":"https://api.github.com/users/mfine/events{/privacy}","received_events_url":"https://api.github.com/users/mfine/received_events","type":"User","site_admin":false},"body":"I know there's been a lot of history around the Slowloris protection here and in the mailing list. This change simply seeks to make the hard-coded value configurable by settings, with a continued default value of 2048 bytes.\r\n\r\nThe current documentation indicates that\r\n\r\n```\r\nEvery time at least 2048 bytes of the request body are read, the timeout is tickled.\r\n```\r\n\r\nwhich suggests that after 2048 bytes of the request body have been processed, through however many reads, the timeout will be tickled. But the current implementation seems to tickle the timeout only after a [single read](https://github.com/yesodweb/wai/blob/master/warp/Network/Wai/Handler/Warp/Run.hs#L478)  consumed at least 2048 bytes. Sending in at least 2048 bytes across multiple writes without any single write at least 2048 bytes will trigger the Slowloris protection. A stateful counter of bytes here that resets on tickle might be useful.\r\n\r\nOur current warp use-case is an IoT application that  POST's low volume telemetry data over long-lived streaming requests. Our devices end up looking a lot like a Slowloris attack :) While in the long run HTTP/2 might be a better fit and its timeout tickling better-suited, we'd still like to be able to use HTTP/1 as well, and configure down the Slowloris prevention value without having to increase the timeout value and lose client responsiveness detection.\r\n\r\nI couldn't piece together in `RunSpec.hs` how the Slowloris prevention was being validated, but would be happy to add a test that checks that the new Slowloris size is honored with a little guidance.\r\n\r\nAnd thanks for the great software! We love running on top of warp!","created_at":"2015-08-05T05:36:29Z","updated_at":"2015-08-05T09:26:17Z","closed_at":"2015-08-05T09:26:17Z","merged_at":"2015-08-05T09:26:17Z","merge_commit_sha":"31ae218dfbdce29943d0341ec992ec05a2e85f52","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/yesodweb/wai/pulls/418/commits","review_comments_url":"https://api.github.com/repos/yesodweb/wai/pulls/418/comments","review_comment_url":"https://api.github.com/repos/yesodweb/wai/pulls/comments{/number}","comments_url":"https://api.github.com/repos/yesodweb/wai/issues/418/comments","statuses_url":"https://api.github.com/repos/yesodweb/wai/statuses/d07252348e4fa9e2ca1200021ac5907295911e98","head":{"label":"mfine:mfine-slowloris-size","ref":"mfine-slowloris-size","sha":"d07252348e4fa9e2ca1200021ac5907295911e98","user":{"login":"mfine","id":60851,"avatar_url":"https://avatars.githubusercontent.com/u/60851?v=3","gravatar_id":"","url":"https://api.github.com/users/mfine","html_url":"https://github.com/mfine","followers_url":"https://api.github.com/users/mfine/followers","following_url":"https://api.github.com/users/mfine/following{/other_user}","gists_url":"https://api.github.com/users/mfine/gists{/gist_id}","starred_url":"https://api.github.com/users/mfine/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mfine/subscriptions","organizations_url":"https://api.github.com/users/mfine/orgs","repos_url":"https://api.github.com/users/mfine/repos","events_url":"https://api.github.com/users/mfine/events{/privacy}","received_events_url":"https://api.github.com/users/mfine/received_events","type":"User","site_admin":false},"repo":{"id":40223929,"name":"wai","full_name":"mfine/wai","owner":{"login":"mfine","id":60851,"avatar_url":"https://avatars.githubusercontent.com/u/60851?v=3","gravatar_id":"","url":"https://api.github.com/users/mfine","html_url":"https://github.com/mfine","followers_url":"https://api.github.com/users/mfine/followers","following_url":"https://api.github.com/users/mfine/following{/other_user}","gists_url":"https://api.github.com/users/mfine/gists{/gist_id}","starred_url":"https://api.github.com/users/mfine/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mfine/subscriptions","organizations_url":"https://api.github.com/users/mfine/orgs","repos_url":"https://api.github.com/users/mfine/repos","events_url":"https://api.github.com/users/mfine/events{/privacy}","received_events_url":"https://api.github.com/users/mfine/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mfine/wai","description":"Haskell Web Application Interface","fork":true,"url":"https://api.github.com/repos/mfine/wai","forks_url":"https://api.github.com/repos/mfine/wai/forks","keys_url":"https://api.github.com/repos/mfine/wai/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mfine/wai/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mfine/wai/teams","hooks_url":"https://api.github.com/repos/mfine/wai/hooks","issue_events_url":"https://api.github.com/repos/mfine/wai/issues/events{/number}","events_url":"https://api.github.com/repos/mfine/wai/events","assignees_url":"https://api.github.com/repos/mfine/wai/assignees{/user}","branches_url":"https://api.github.com/repos/mfine/wai/branches{/branch}","tags_url":"https://api.github.com/repos/mfine/wai/tags","blobs_url":"https://api.github.com/repos/mfine/wai/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mfine/wai/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mfine/wai/git/refs{/sha}","trees_url":"https://api.github.com/repos/mfine/wai/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mfine/wai/statuses/{sha}","languages_url":"https://api.github.com/repos/mfine/wai/languages","stargazers_url":"https://api.github.com/repos/mfine/wai/stargazers","contributors_url":"https://api.github.com/repos/mfine/wai/contributors","subscribers_url":"https://api.github.com/repos/mfine/wai/subscribers","subscription_url":"https://api.github.com/repos/mfine/wai/subscription","commits_url":"https://api.github.com/repos/mfine/wai/commits{/sha}","git_commits_url":"https://api.github.com/repos/mfine/wai/git/commits{/sha}","comments_url":"https://api.github.com/repos/mfine/wai/comments{/number}","issue_comment_url":"https://api.github.com/repos/mfine/wai/issues/comments{/number}","contents_url":"https://api.github.com/repos/mfine/wai/contents/{+path}","compare_url":"https://api.github.com/repos/mfine/wai/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mfine/wai/merges","archive_url":"https://api.github.com/repos/mfine/wai/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mfine/wai/downloads","issues_url":"https://api.github.com/repos/mfine/wai/issues{/number}","pulls_url":"https://api.github.com/repos/mfine/wai/pulls{/number}","milestones_url":"https://api.github.com/repos/mfine/wai/milestones{/number}","notifications_url":"https://api.github.com/repos/mfine/wai/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mfine/wai/labels{/name}","releases_url":"https://api.github.com/repos/mfine/wai/releases{/id}","created_at":"2015-08-05T04:16:58Z","updated_at":"2015-08-05T04:17:00Z","pushed_at":"2015-08-05T05:01:15Z","git_url":"git://github.com/mfine/wai.git","ssh_url":"git@github.com:mfine/wai.git","clone_url":"https://github.com/mfine/wai.git","svn_url":"https://github.com/mfine/wai","homepage":"","size":3434,"stargazers_count":0,"watchers_count":0,"language":"Haskell","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"yesodweb:master","ref":"master","sha":"e3fd9a26579370fcdcdec8d962eb8bd5df9a9e82","user":{"login":"yesodweb","id":930379,"avatar_url":"https://avatars.githubusercontent.com/u/930379?v=3","gravatar_id":"","url":"https://api.github.com/users/yesodweb","html_url":"https://github.com/yesodweb","followers_url":"https://api.github.com/users/yesodweb/followers","following_url":"https://api.github.com/users/yesodweb/following{/other_user}","gists_url":"https://api.github.com/users/yesodweb/gists{/gist_id}","starred_url":"https://api.github.com/users/yesodweb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yesodweb/subscriptions","organizations_url":"https://api.github.com/users/yesodweb/orgs","repos_url":"https://api.github.com/users/yesodweb/repos","events_url":"https://api.github.com/users/yesodweb/events{/privacy}","received_events_url":"https://api.github.com/users/yesodweb/received_events","type":"Organization","site_admin":false},"repo":{"id":476179,"name":"wai","full_name":"yesodweb/wai","owner":{"login":"yesodweb","id":930379,"avatar_url":"https://avatars.githubusercontent.com/u/930379?v=3","gravatar_id":"","url":"https://api.github.com/users/yesodweb","html_url":"https://github.com/yesodweb","followers_url":"https://api.github.com/users/yesodweb/followers","following_url":"https://api.github.com/users/yesodweb/following{/other_user}","gists_url":"https://api.github.com/users/yesodweb/gists{/gist_id}","starred_url":"https://api.github.com/users/yesodweb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yesodweb/subscriptions","organizations_url":"https://api.github.com/users/yesodweb/orgs","repos_url":"https://api.github.com/users/yesodweb/repos","events_url":"https://api.github.com/users/yesodweb/events{/privacy}","received_events_url":"https://api.github.com/users/yesodweb/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/yesodweb/wai","description":"Haskell Web Application Interface","fork":false,"url":"https://api.github.com/repos/yesodweb/wai","forks_url":"https://api.github.com/repos/yesodweb/wai/forks","keys_url":"https://api.github.com/repos/yesodweb/wai/keys{/key_id}","collaborators_url":"https://api.github.com/repos/yesodweb/wai/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/yesodweb/wai/teams","hooks_url":"https://api.github.com/repos/yesodweb/wai/hooks","issue_events_url":"https://api.github.com/repos/yesodweb/wai/issues/events{/number}","events_url":"https://api.github.com/repos/yesodweb/wai/events","assignees_url":"https://api.github.com/repos/yesodweb/wai/assignees{/user}","branches_url":"https://api.github.com/repos/yesodweb/wai/branches{/branch}","tags_url":"https://api.github.com/repos/yesodweb/wai/tags","blobs_url":"https://api.github.com/repos/yesodweb/wai/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/yesodweb/wai/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/yesodweb/wai/git/refs{/sha}","trees_url":"https://api.github.com/repos/yesodweb/wai/git/trees{/sha}","statuses_url":"https://api.github.com/repos/yesodweb/wai/statuses/{sha}","languages_url":"https://api.github.com/repos/yesodweb/wai/languages","stargazers_url":"https://api.github.com/repos/yesodweb/wai/stargazers","contributors_url":"https://api.github.com/repos/yesodweb/wai/contributors","subscribers_url":"https://api.github.com/repos/yesodweb/wai/subscribers","subscription_url":"https://api.github.com/repos/yesodweb/wai/subscription","commits_url":"https://api.github.com/repos/yesodweb/wai/commits{/sha}","git_commits_url":"https://api.github.com/repos/yesodweb/wai/git/commits{/sha}","comments_url":"https://api.github.com/repos/yesodweb/wai/comments{/number}","issue_comment_url":"https://api.github.com/repos/yesodweb/wai/issues/comments{/number}","contents_url":"https://api.github.com/repos/yesodweb/wai/contents/{+path}","compare_url":"https://api.github.com/repos/yesodweb/wai/compare/{base}...{head}","merges_url":"https://api.github.com/repos/yesodweb/wai/merges","archive_url":"https://api.github.com/repos/yesodweb/wai/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/yesodweb/wai/downloads","issues_url":"https://api.github.com/repos/yesodweb/wai/issues{/number}","pulls_url":"https://api.github.com/repos/yesodweb/wai/pulls{/number}","milestones_url":"https://api.github.com/repos/yesodweb/wai/milestones{/number}","notifications_url":"https://api.github.com/repos/yesodweb/wai/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/yesodweb/wai/labels{/name}","releases_url":"https://api.github.com/repos/yesodweb/wai/releases{/id}","created_at":"2010-01-17T15:44:09Z","updated_at":"2015-07-31T17:15:07Z","pushed_at":"2015-08-05T09:26:17Z","git_url":"git://github.com/yesodweb/wai.git","ssh_url":"git@github.com:yesodweb/wai.git","clone_url":"https://github.com/yesodweb/wai.git","svn_url":"https://github.com/yesodweb/wai","homepage":"","size":6415,"stargazers_count":287,"watchers_count":287,"language":"Haskell","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":111,"mirror_url":null,"open_issues_count":9,"forks":111,"open_issues":9,"watchers":287,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/yesodweb/wai/pulls/418"},"html":{"href":"https://github.com/yesodweb/wai/pull/418"},"issue":{"href":"https://api.github.com/repos/yesodweb/wai/issues/418"},"comments":{"href":"https://api.github.com/repos/yesodweb/wai/issues/418/comments"},"review_comments":{"href":"https://api.github.com/repos/yesodweb/wai/pulls/418/comments"},"review_comment":{"href":"https://api.github.com/repos/yesodweb/wai/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/yesodweb/wai/pulls/418/commits"},"statuses":{"href":"https://api.github.com/repos/yesodweb/wai/statuses/d07252348e4fa9e2ca1200021ac5907295911e98"}},"merged":true,"mergeable":null,"mergeable_state":"unknown","merged_by":{"login":"snoyberg","id":49415,"avatar_url":"https://avatars.githubusercontent.com/u/49415?v=3","gravatar_id":"","url":"https://api.github.com/users/snoyberg","html_url":"https://github.com/snoyberg","followers_url":"https://api.github.com/users/snoyberg/followers","following_url":"https://api.github.com/users/snoyberg/following{/other_user}","gists_url":"https://api.github.com/users/snoyberg/gists{/gist_id}","starred_url":"https://api.github.com/users/snoyberg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/snoyberg/subscriptions","organizations_url":"https://api.github.com/users/snoyberg/orgs","repos_url":"https://api.github.com/users/snoyberg/repos","events_url":"https://api.github.com/users/snoyberg/events{/privacy}","received_events_url":"https://api.github.com/users/snoyberg/received_events","type":"User","site_admin":false},"comments":1,"review_comments":0,"commits":1,"additions":18,"deletions":6,"changed_files":4}}