Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cgi.FieldStorage, multipart, missing Content-Length #64703

Closed
srittau mannequin opened this issue Feb 3, 2014 · 16 comments
Closed

cgi.FieldStorage, multipart, missing Content-Length #64703

srittau mannequin opened this issue Feb 3, 2014 · 16 comments
Labels
3.7 (EOL) end of life 3.8 only security fixes 3.9 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@srittau
Copy link
Mannequin

srittau mannequin commented Feb 3, 2014

BPO 20504
Nosy @srittau, @vstinner, @benjaminp, @ned-deily, @smurfix, @PierreQuentel, @berkerpeksag, @miss-islington
PRs
  • bpo-20504 : fix issue in cgi.py when a multipart/form-data request has no content-length #10634
  • bpo-20504 : in cgi.py, fix bug when a multipart/form-data request has… #10638
  • [3.8] bpo-20504 : in cgi.py, fix bug when a multipart/form-data request has… (GH-10638) #15919
  • [3.7] bpo-20504 : in cgi.py, fix bug when a multipart/form-data request has… (GH-10638) #15920
  • Files
  • cgi-bug.py: test case
  • cgi.patch
  • issue20504.diff
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2019-09-29.13:12:14.878>
    created_at = <Date 2014-02-03.21:33:19.147>
    labels = ['3.7', '3.8', 'type-bug', 'library', '3.9']
    title = 'cgi.FieldStorage, multipart, missing Content-Length'
    updated_at = <Date 2019-09-29.13:12:14.875>
    user = 'https://github.com/srittau'

    bugs.python.org fields:

    activity = <Date 2019-09-29.13:12:14.875>
    actor = 'ned.deily'
    assignee = 'none'
    closed = True
    closed_date = <Date 2019-09-29.13:12:14.878>
    closer = 'ned.deily'
    components = ['Library (Lib)']
    creation = <Date 2014-02-03.21:33:19.147>
    creator = 'srittau'
    dependencies = []
    files = ['33891', '35551', '40833']
    hgrepos = []
    issue_num = 20504
    keywords = ['patch']
    message_count = 16.0
    messages = ['210166', '220159', '220160', '220161', '220179', '252541', '253303', '253322', '253323', '326895', '326968', '330210', '351821', '351836', '351838', '353492']
    nosy_count = 9.0
    nosy_names = ['srittau', 'vstinner', 'benjamin.peterson', 'ned.deily', 'smurfix', 'quentel', 'berker.peksag', 'pdgoins-work', 'miss-islington']
    pr_nums = ['10634', '10638', '15919', '15920']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue20504'
    versions = ['Python 3.7', 'Python 3.8', 'Python 3.9']

    @srittau
    Copy link
    Mannequin Author

    srittau mannequin commented Feb 3, 2014

    Consider the attached test case. This test will run fine with Python 2.7, but will fail with Python 3.3. If cgi.FieldStorage() tries to parse a multipart request without a Content-Length header in the main section, segments will have a length of 0.

    During the parse process, two instances of FieldStorage are involved. The outer one reads the whole request and creates and delegates reading of the fragment to inner instances.

    The main problem is that FieldStorage.read_lines_to_outerboundary() of the inner FieldStorage will read nothing, since self.limit is lower than zero.

        def read_lines_to_outerboundary(self):
            ...
            while 1:
                if _read >= self.limit:
                    break
            ...

    This happens, since limit is passed when creating the inner instance in FieldStorage.read_multi():

        def read_multi(self, environ, keep_blank_values, strict_parsing):
            ...
                part = klass(self.fp, headers, ib, environ, keep_blank_values,
                             strict_parsing,self.limit-self.bytes_read,
                             self.encoding, self.errors)
            ...

    Now, if the total request did not have a Content-Length header, self.limit will be -1.

    The naive fix works for the test case, at least, but I don't know if there are other repercussions:

    --- /usr/lib/python3.3/cgi.py	2014-02-03 22:31:16.649431125 +0100
    +++ cgi.py	2014-02-03 22:32:14.849704379 +0100
    @@ -788,7 +788,7 @@
             last_line_lfend = True
             _read = 0
             while 1:
    -            if _read >= self.limit:
    +            if self.limit >= 0 and _read >= self.limit:
                     break
                 line = self.fp.readline(1<<16) # bytes
                 self.bytes_read += len(line)

    @srittau srittau mannequin added the stdlib Python modules in the Lib dir label Feb 3, 2014
    @srittau srittau mannequin added the type-bug An unexpected behavior, bug, or error label Feb 26, 2014
    @smurfix
    Copy link
    Mannequin

    smurfix mannequin commented Jun 10, 2014

    Actually, the problem is cgi.py around line 550:

        clen = -1
        if 'content-length' in self.headers:
            try:
                clen = int(self.headers['content-length'])
            except ValueError:
                pass
            if maxlen and clen > maxlen:
                raise ValueError('Maximum content length exceeded')
        self.length = clen
        if self.limit is None and clen:
            self.limit = clen
    

    … so self.limit ends up being -1 instead of None. :-/

    Somebody please change this test to

            if self.limit is None and clen >= 0:

    @smurfix
    Copy link
    Mannequin

    smurfix mannequin commented Jun 10, 2014

    Patch attached.

    @smurfix
    Copy link
    Mannequin

    smurfix mannequin commented Jun 10, 2014

    This also applies to 3.4 and 3.5.

    @ned-deily
    Copy link
    Member

    Thanks for the report, the test case, and the patch. It would be helpful if the informal test could be turned into a patch as a formal test in Lib/test_cgi.py and if, Matthias, you would be willing to sign the PSF contributor agreement if you haven't already (https://www.python.org/psf/contrib/contrib-form/).

    @srittau
    Copy link
    Mannequin Author

    srittau mannequin commented Oct 8, 2015

    Is there any progress on this? The fix seems trivial.

    @berkerpeksag
    Copy link
    Member

    The attached patch(cgi.patch) doesn't fix the problem for me: cgi-bug.py still fails with a TypeError. Here is a patch with a test to fix the problem.

    With bpo-20504.diff applied:

    $ ./python t.py 
    5

    (Only changed the "assert len(fields["my-arg"].file.read()) == 5" line with "print(len(fields["my-arg"].file.read()))")

    @vstinner
    Copy link
    Member

    See also issue bpo-24764: "cgi.FieldStorage.read_multi ignores Content-Length" (changeset 11e9f34169d1).

    @vstinner
    Copy link
    Member

    I reviewed bpo-20504.diff on Rietveld.

    @pdgoins-work
    Copy link
    Mannequin

    pdgoins-work mannequin commented Oct 2, 2018

    I'm just going to ping on this issue. It looks like this has just slipped off the radar. I've seen the last diff and the code review, but it seems that this just needs some final follow-up on the code review comments, no?

    I could easily do the final cleanup myself, but would prefer to let someone already on this thread take it across the finish line since I didn't do any of the real work for this patch. If really necessary, I may be able to clean this up if no one else can spare the time.

    @smurfix
    Copy link
    Mannequin

    smurfix mannequin commented Oct 3, 2018

    Owch, yeah, this fell off the radar.

    Anyway, I've signed the CLA, so if somebody could finish and apply this I'd be grateful. Myself, I unfortunately don't have the time.

    @smurfix smurfix mannequin added 3.7 (EOL) end of life 3.8 only security fixes labels Oct 3, 2018
    @PierreQuentel
    Copy link
    Mannequin

    PierreQuentel mannequin commented Nov 21, 2018

    I have submitted PR bpo-10638 to fix this issue.

    @benjaminp
    Copy link
    Contributor

    New changeset 2d7caca by Benjamin Peterson (Pierre Quentel) in branch 'master':
    bpo-20504 : in cgi.py, fix bug when a multipart/form-data request has… (bpo-10638)
    2d7caca

    @miss-islington
    Copy link
    Contributor

    New changeset e3bd941 by Miss Islington (bot) in branch '3.8':
    bpo-20504 : in cgi.py, fix bug when a multipart/form-data request has… (GH-10638)
    e3bd941

    @miss-islington
    Copy link
    Contributor

    New changeset 99f0e81 by Miss Islington (bot) in branch '3.7':
    bpo-20504 : in cgi.py, fix bug when a multipart/form-data request has… (GH-10638)
    99f0e81

    @PierreQuentel
    Copy link
    Mannequin

    PierreQuentel mannequin commented Sep 29, 2019

    Now that the PR has been merged, can someone close the issue ?

    @ned-deily ned-deily added the 3.9 only security fixes label Sep 29, 2019
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.7 (EOL) end of life 3.8 only security fixes 3.9 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    5 participants