IanMitchell / discord-notifier

A ruby wrapper around Discord webhooks
MIT License
14 stars 4 forks source link

message: "Cannot send an empty message" - code: 50006 #11

Closed quirinux closed 4 years ago

quirinux commented 4 years ago

weird thing suddenly started happening, I am getting the following message when sending an embed message to any webhook:

HTTP Status Code: 400 Response Body: {"message": "Cannot send an empty message", "code": 50006}"

On lib/discord_notifier.rb line #50 on self.send_request(params) reads:

    def self.send_request(params)
      Net::HTTP.post endpoint(params),
                     params.to_json,
                     'Content-Type': 'application/json'
    end

Which looks fine as far as I understood, but there is something happening here that Discrod's API is complaining, so I changed the statement a little bit to get more control over the request and ended up having:

    def self.send_request(params)
      uri = endpoint(params)
      Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
        req = Net::HTTP::Post.new(uri)
        req['Content-Type'] = 'application/json'
        req.body = params.to_json
        http.request(req)
      end
    end

Inspecting the request I found that the second sends out a Connection Header set to close, ["HTTP_CONNECTION","close"], and to be honest I have no idea if that could be the issue or else if the wait flag influences on the api now

Anyways:

  1. further investigation is needed
  2. my fix is forcing SSL, need to handle this in a better manner

I would propose to PR a fix, do I keep the old approach and a new one with a flag or method call to differ each of them? Does it make any sense?

I'm running on ruby-2.5.3

IanMitchell commented 4 years ago

Hello! Apologies for the delay in response - getting back from a vacation. Will take a look at this tomorrow!

quirinux commented 4 years ago

no bother @IanMitchell, take your time and let me know if you need any hand with it

IanMitchell commented 4 years ago

Might as well take this opportunity to switch to GitHub Actions too 👀

IanMitchell commented 4 years ago

Put up a WIP branch, might not have time to really dig into this until after Thanksgiving but I'll let you know what I find out!

IanMitchell commented 4 years ago

@quirinux would you mind posting example code for how you're calling the notifier gem right now?

IanMitchell commented 4 years ago

@sas145alex are you seeing the same error? I'm not seeing it reproduce when I run the following quick test script:

Discord::Notifier.setup do |config|
  config.url = 'WEBOOK'
  config.username = 'Discord Notifier'
end

embed = Discord::Embed.new do
  title "Discord Ruby Notification"
  description "Will it work?"
end

Discord::Notifier.message(embed)
IanMitchell commented 4 years ago

Oh just kidding, one of my Rails applications is being impacted by this too, just not seeing any logging from it... interesting.

IanMitchell commented 4 years ago

I downgraded to Ruby 2.5.3 and I'm seeing the same issue locally now. I upgraded my Rails application to ruby 2.6.5 and the issue was fixed - so short term, I would recommend that route if you can. Will continue to poke at the Ruby 2.5.3 issue though

gmjosack commented 4 years ago

Can you compare what the HTTP requests look like coming from the different versions of ruby? When i tested a simple http request from 2.5.1 it worked fine so it'd be good to know what the request looks like compared to the two versions. And easy test is to run something like nc -l localhost 8888 and point the endpoint at http://localhost:8888

IanMitchell commented 4 years ago

@gmjosack thanks for the tip! That is super useful. Yeah, definitely shows the problem - for some reason the Content Type is being overridden

2.5.3:

POST /?wait=true HTTP/1.1
Content-Type: application/json
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept: */*
User-Agent: Ruby
Host: localhost:8888
Content-Length: 152
Content-Type: application/x-www-form-urlencoded

{"url":"http://localhost:8888","username":"Discord Notifier","wait":true,"embeds":[{"title":"Discord Ruby Notification","description":"Will it work?"}]}

2.6.5

POST /?wait=true HTTP/1.1
Content-Type: application/json
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept: */*
User-Agent: Ruby
Host: localhost:8888
Content-Length: 152

{"url":"http://localhost:8888","username":"Discord Notifier","wait":true,"embeds":[{"title":"Discord Ruby Notification","description":"Will it work?"}]}
gmjosack commented 4 years ago

Yeah, previously, by accident, the API would parse json even when receiving the form-urlencoded content type. This bug was fixed but had the unfortunate side-effect of breaking clients with invalid requests that previously worked by coincidence. I'm not really sure why ruby is ignoring your header here :X

IanMitchell commented 4 years ago

Figured it out! This needs to be a hash: https://github.com/IanMitchell/discord-notifier/blob/master/lib/discord_notifier.rb#L53

Many thanks for the tip, made this so much easier haha. Working on verifying the fix + getting it out now

gmjosack commented 4 years ago

Awesome! glad i could help :)

IanMitchell commented 4 years ago

Ok, should be published. Let me know if I messed anything up, been a while since I've done this heheh

quirinux commented 4 years ago

sorry for the delay in reply, but ya, I had noticed that app/jaon and form-encoded were been both sent on request header, apologies I should have included that on this issue.

Anyway I just tested the 1.0.3 version and it is working like a charm again, thanks a much.

Just for the sake of the records follow how I normally sent a message out

  def send_notification(message)
    avatar_url = message[:avatar] 
    username = message[:username] 
    webhook = message[:webhook]
    raise "No webhook found for channel" if webhook.blank?
    embed = Discord::Embed.new do
      title message[:title] unless message[:title].blank?
      color message[:colour] unless message[:colour].blank?
      footer(text: message[:footer]) unless message[:footer].blank?
      message[:fields].each do |f|
        next if f[:value].blank?
        field(
          "name": f[:name],
          "value":f[:value],
          "inline": f[:inline]
        )
      end
    end
    @log.debug 'send_notification', embed: embed.data
    Discord::Notifier.message(embed, url: webhook, username: username, avatar_url: avatar_url)
  end
IanMitchell commented 4 years ago

All good! Glad to hear it’s working now 😁. Thanks for the bug report!