socketry / async-http

MIT License
320 stars 46 forks source link

async-http block by Cloudflare but Net::HTTP and Faraday doesn't #190

Open elct9620 opened 11 hours ago

elct9620 commented 11 hours ago

I am trying to build a Discord application, the document explains the user agent is necessary to prevent Cloudflare from returning 400 errors.

To make a PoC I write below Ruby code.

API_VERSION = 10
CHANNEL_ID = "xxxx"

Sync do
  Async::HTTP::Internet.post(
    Async::HTTP::Endpoint.parse("https://discord.com/api/v#{API_VERSION}/channels/#{CHANNEL_ID}/messages"),
    {
      'Content-Type' => 'application/json',
      'Authorization' => "Bot #{ENV['DISCORD_BOT_TOKEN']}",
      'User-Agent' => 'DiscordBot (https://example.com 0.1.0)'
    },
    { content: "Hello World" }.to_json
  )
end

The response is 400 bad request from Cloudflare.

However, if using Net::HTTP (ref: discorb) or Faraday is works correctly.

Faraday.post(
  "https://discord.com/api/v#{API_VERSION}/channels/#{CHANNEL_ID}/messages",
  { content: 'Hello World' }.to_json,
  {
      'Content-Type' => 'application/json',
      'Authorization' => "Bot #{ENV['DISCORD_BOT_TOKEN']}",
      'User-Agent' => 'DiscordBot (https://example.com 0.1.0)' # Optional, the "Faraday 2.12.7" as user agent is work
  }
)

On my website, if the bot filter is enabled the Net::HTTP isn't work. But Discord still accepts Net::HTTP requests, I guess there are some behaviors detected by Cloudflare and blocked it.

ioquatix commented 9 hours ago

Can you try again using lower case headers, e.g. authorization, content-type and user-agent?

elct9620 commented 8 hours ago

I had tried user-agent and it did not work, too.

I also changed the user agent, which is unrelated to the user agent that is sent to Discord.

Sync do
  Async::HTTP::Internet.post(
    Async::HTTP::Endpoint.parse("https://discord.com/api/v#{API_VERSION}/channels/#{CHANNEL_ID}/messages"),
    {
      'Content-Type' => 'application/json',
      'Authorization' => "Bot #{ENV['DISCORD_BOT_TOKEN']}",
      'User-Agent' => 'Faraday 2.17.2' # use Faraday user-agent is not work
    },
    { content: "Hello World" }.to_json
  )
end
ioquatix commented 8 hours ago

Faraday and Net::HTTP both only support HTTP/1 so that may be a difference.

What response are you getting back?

elct9620 commented 8 hours ago

Just got 400 bad request message from Cloudflare

=> #<Async::HTTP::Protocol::HTTP2::Response:0x63d8 status=400>
irb(main):002> res.body.read
=> "<html>\r\n<head><title>400 Bad Request</title></head>\r\n<body>\r\n<center><h1>400 Bad Request</h1></center>\r\n<hr><center>cloudflare</center>\r\n</body>\r\n</html>\r\n"
ioquatix commented 6 hours ago

Okay, I'll investigate.