Skip to content

Support other optional parameters and quoted-strings on Content-Type parser#35549

Merged
kamipo merged 1 commit intorails:masterfrom
r7kamura:feature/response-charset
Mar 10, 2019
Merged

Support other optional parameters and quoted-strings on Content-Type parser#35549
kamipo merged 1 commit intorails:masterfrom
r7kamura:feature/response-charset

Conversation

@r7kamura
Copy link
Contributor

@r7kamura r7kamura commented Mar 9, 2019

Summary

There is a possibility that Content-Type header includes optional parameters other than charset.

As an example, to indicate the presence or absence of the header line, text/csv type has optional header parameter like this:

Content-Type: text/csv; charset=utf-16; header=present

To exclude this type of optional parameters from #charset, I changed #parse_content_type implementation in this pull request.

Other Information

@rails-bot rails-bot bot added the actionpack label Mar 9, 2019
@r7kamura r7kamura changed the title Support optional parameters on Content-Type parser Exclude Content-Type optional parameters from #charset Mar 9, 2019
@r7kamura r7kamura force-pushed the feature/response-charset branch from e439c35 to 52e6eee Compare March 9, 2019 06:41
Copy link
Member

@kamipo kamipo Mar 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about extract more descriptive regex as CONTENT_TYPE_PARSER?

    CONTENT_TYPE_PARSER = /\A(?<type>[^;\s]+)(?:\s*;\s*charset=(?<charset>[^;\s]+))?/ # :nodoc:

    def parse_content_type(content_type)
      if content_type && match = CONTENT_TYPE_PARSER.match(content_type)
        ContentTypeHeader.new(match[:type], match[:charset])
      else
        NullContentTypeHeader
      end
    end

Copy link
Contributor Author

@r7kamura r7kamura Mar 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. I'll change it soon.

By the way, https://tools.ietf.org/html/rfc7231#section-3.1.1.1 says text/csv; charset="utf-16" is a valid representation of Content-Type. I don't know if we should support this quoted-string in this pull request. What do you think of this, @kamipo? If we support this type of quoted-string, I think we have no choice but to use Regexp here anyway.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm fine to support quoted-string, that is easer and no complex.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I'm trying to support these patterns by Regexp parser, but it's not so simple...

text/csv; charset="utf-16"; header=present
text/csv; header=present; charset="utf-16"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does any client send the text/csv; header=present; charset="utf-16"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, it could make just one regex.

    CONTENT_TYPE_PARSER = /\A(?<type>[^;\s]+)(?:.*;\s*charset=(?<quote>"?)(?<charset>[^;\s]+)\k<quote>)?/ # :nodoc:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does any client send the text/csv; header=present; charset="utf-16"?

ah, a Rails app in our company has this kind of code... 😇
(To be accurate, our app returns text/csv; header=present; charset=sjis)

Anyway, it could make just one regex.

Awesome! I pushed dc3c2ec, but slightly changed its Regexp like this:

/\A(?<type>[^;\s]+)?(?:.*;\s*charset=(?<quote>"?)(?<charset>[^;\s]+)\k<quote>)?/
                   ^
              added this `?`

This is because its Content-Type might be half-cooked on #parsed_content_type_header and this make some existent tests to be failed. The code below is an example from test/dispatch/response_test.rb:

test "response charset and content type from railsish app" do
  @app = lambda { |env|
    ActionDispatch::Response.new.tap { |resp|
      resp.charset = "utf-16"
      # resp.headers['Content-Type'] #=> "; charset=utf-16" OMG ;(
      resp.content_type = Mime[:xml]
      resp.body = "Hello"
      resp.request = ActionDispatch::Request.empty
    }.to_a
  }

  get "/"
  assert_response :success

  assert_equal("utf-16", @response.charset)
  assert_equal(Mime[:xml], @response.content_type)

  assert_equal("application/xml; charset=utf-16", @response.headers["Content-Type"])
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# resp.headers['Content-Type'] #=> "; charset=utf-16" OMG ;(

I see... nice catch 👍

@r7kamura r7kamura changed the title Exclude Content-Type optional parameters from #charset Support other optional parameters and quoted-strings on Content-Type parser Mar 10, 2019
Copy link
Member

@kamipo kamipo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.
Can you squash your commits?

@r7kamura r7kamura force-pushed the feature/response-charset branch from dc3c2ec to 29b42f5 Compare March 10, 2019 07:49
@kamipo kamipo merged commit 08a93ef into rails:master Mar 10, 2019
@kamipo
Copy link
Member

kamipo commented Mar 10, 2019

Thanks!

kamipo added a commit that referenced this pull request Mar 10, 2019
Support other optional parameters and quoted-strings on Content-Type parser
@r7kamura r7kamura deleted the feature/response-charset branch March 10, 2019 08:44
jhawthorn added a commit to jhawthorn/rails that referenced this pull request Mar 22, 2019
rafaelfranca added a commit that referenced this pull request Mar 22, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants