Edgewall Software
Modify

Opened 4 months ago

Closed 5 days ago

#13701 closed defect (fixed)

UnicodeEncodeError in trac/web/_fcgi.py", line 1212

Reported by: gavin.kou@… Owned by: Jun Omae
Priority: normal Milestone: 1.6.1
Component: web frontend Version: 1.6
Severity: major Keywords: fcgi
Cc: Branch:
Release Notes:
  • Fixed ETag header with non-ascii characters is generated from check_modified() when req.authname has non latin-1 characters.
  • Verify latin-1 characters only are used in status and headers when WSGIServer._start_response is invoked.
API Changes:
Internal Changes:

Description (last modified by Jun Omae)

this error caused 500 error the click the attachment in ticket.

source:/branches/1.6-stable/trac/web/_fcgi.py#L1212

fixed the issue by added 'ignore' in encode method.

2024-01-06 10:19:57,084 Trac[main] ERROR: [127.0.0.1] Internal Server Error: <RequestWithSession "GET '/attachment/ticket/8/2023è\x92\x99æ\x96°å\x86¬ä»¤è\x90¥_代ç\x90\x86ä»·.png'">, referrer 'https://trac.foo.bar/ticket/8'
Traceback (most recent call last):
  File "/u0/app/trac/lib64/python3.11/site-packages/trac/web/main.py", line 609, in dispatch_request
    dispatcher.dispatch(req)
  File "/u0/app/trac/lib64/python3.11/site-packages/trac/web/main.py", line 301, in dispatch
    raise e
  File "/u0/app/trac/lib64/python3.11/site-packages/trac/web/main.py", line 266, in dispatch
    req.send(output, content_type or 'text/html')
  File "/u0/app/trac/lib64/python3.11/site-packages/trac/web/api.py", line 875, in send
    self._send(content, content_type, status)
  File "/u0/app/trac/lib64/python3.11/site-packages/trac/web/api.py", line 1011, in _send
    self.write(content)
  File "/u0/app/trac/lib64/python3.11/site-packages/trac/web/api.py", line 977, in write
    self._write(b''.join(buf))
  File "/u0/app/trac/lib64/python3.11/site-packages/trac/web/_fcgi.py", line 1212, in write
    req.stdout.write(_str_join(generator()).encode('iso-8859-1'))
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 25-26: ordinal not in range(256)

Attachments (0)

Change History (9)

comment:1 by Jun Omae, 4 months ago

Component: web frontend/mod_wsgiweb frontend
Description: modified (diff)
Keywords: fcgi added; UnicodeEncodeError removed

comment:2 by Jun Omae, 4 months ago

Unable to reproduce it.

  1. Create new ticket
  2. Attach 2023蒙新冬令营_代理价.png to the created ticket
  3. Click the attachment link and download link in attachments area
    • It works fine

Please provide more information. Also, are you using non-ascii characters in username?

Request and response headers

$ curl -s -v -o /dev/null 'http://127.0.0.1:3000/trac/attachment/ticket/22/2023%E8%92%99%E6%96%B0%E5%86%AC%E4%BB%A4%E8%90%A5_%E4%BB%A3%E7%90%86%E4%BB%B7.png'
*   Trying 127.0.0.1:3000...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0)
> GET /trac/attachment/ticket/22/2023%E8%92%99%E6%96%B0%E5%86%AC%E4%BB%A4%E8%90%A5_%E4%BB%A3%E7%90%86%E4%BB%B7.png HTTP/1.1
> Host: 127.0.0.1:3000
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 Ok
< Date: Sun, 07 Jan 2024 00:59:55 GMT
< Server: Apache/2.4.41 (Ubuntu) mod_fcgid/2.3.9 SVN/1.13.0
< Cache-Control: must-revalidate
< Expires: Fri, 01 Jan 1999 00:00:00 GMT
< Set-Cookie: trac_form_token=100da4f5f95c660e3a38a3d6; HttpOnly; Path=/trac
< Set-Cookie: trac_session=0dfdef1f495a05b018e39431; expires=Sat, 06 Apr 2024 00:59:55 GMT; HttpOnly; Path=/trac
< ETag: W/"anonymous/Sun, 07 Jan 2024 00:34:17 GMT/False"
< Transfer-Encoding: chunked
< Content-Type: text/html;charset=utf-8
<
{ [7143 bytes data]
* Connection #0 to host 127.0.0.1 left intact
$ curl -s -v -o /dev/null 'http://127.0.0.1:3000/trac/raw-attachment/ticket/22/2023%E8%92%99%E6%96%B0%E5%86%AC%E4%BB%A4%E8%90%A5_%E4%BB%A3%E7%90%86%E4%BB%B7.png'
*   Trying 127.0.0.1:3000...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0)
> GET /trac/raw-attachment/ticket/22/2023%E8%92%99%E6%96%B0%E5%86%AC%E4%BB%A4%E8%90%A5_%E4%BB%A3%E7%90%86%E4%BB%B7.png HTTP/1.1
> Host: 127.0.0.1:3000
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 Ok
< Date: Sun, 07 Jan 2024 01:00:01 GMT
< Server: Apache/2.4.41 (Ubuntu) mod_fcgid/2.3.9 SVN/1.13.0
< Content-Disposition: attachment
< Set-Cookie: trac_session=365e7bac7277b25146747bea; expires=Sat, 06 Apr 2024 01:00:01 GMT; HttpOnly; Path=/trac
< ETag: W/"anonymous/Sun, 07 Jan 2024 00:34:17 GMT/False"
< Content-Length: 12134
< Last-Modified: Sun, 07 Jan 2024 00:34:17 GMT
< Content-Type: image/png; charset=iso-8859-15
<
{ [12134 bytes data]
* Connection #0 to host 127.0.0.1 left intact

in reply to:  description ; comment:3 by Jun Omae, 4 months ago

Milestone: 1.6.1
Owner: set to Jun Omae
Status: newassigned

Replying to gavin.kou@…:

fixed the issue by added 'ignore' in encode method.

Instead, try the following patch:

  • trac/web/_fcgi.py

    diff --git a/trac/web/_fcgi.py b/trac/web/_fcgi.py
    index 12d04a6b4..10cf92bd4 100644
    a b class WSGIServer(Server):  
    12091209                    for header in headers:
    12101210                        yield '%s: %s\r\n' % header
    12111211                    yield '\r\n'
    1212                 req.stdout.write(_str_join(generator()).encode('iso-8859-1'))
     1212                req.stdout.write(_str_join(generator()).encode('utf-8'))
    12131213
    12141214            req.stdout.write(data)
    12151215            req.stdout.flush()

comment:4 by anonymous, 4 months ago

thanks so much for quick fixing.

that's a attachment with chinese characters, as right as you commented in #comment:2

the trac 1.6 is running with Python 3.11.2 behind Nginx with fastcgi interface.

i have tried Python 3.5 as well , which mentioned in wiki:TracDownload#Trac16StableRelease , this UnicodeEncodeError occured too.

will verify the changing .encode('iso-8859-1', 'ignore') to .encode('utf-8').

keep posted.

in reply to:  3 comment:5 by gavin.kou@…, 4 months ago

Replying to Jun Omae:

verified, this patch works!

thanks, so much.

$ cat -n "/u0/app/trac/lib64/python3.11/site-packages/trac/web/_fcgi.py" | grep 1212 -A 3 -B 3
  1209                      for header in headers:
  1210                          yield '%s: %s\r\n' % header
  1211                      yield '\r\n'
  1212                  #req.stdout.write(_str_join(generator()).encode('iso-8859-1','ignore'))
  1213                  req.stdout.write(_str_join(generator()).encode('utf-8'))
  1214
  1215              req.stdout.write(data)

$ 

Replying to gavin.kou@…:

fixed the issue by added 'ignore' in encode method.

Instead, try the following patch:

  • trac/web/_fcgi.py

    diff --git a/trac/web/_fcgi.py b/trac/web/_fcgi.py
    index 12d04a6b4..10cf92bd4 100644
    a b class WSGIServer(Server):  
    12091209                    for header in headers:
    12101210                        yield '%s: %s\r\n' % header
    12111211                    yield '\r\n'
    1212                 req.stdout.write(_str_join(generator()).encode('iso-8859-1'))
     1212                req.stdout.write(_str_join(generator()).encode('utf-8'))
    12131213
    12141214            req.stdout.write(data)
    12151215            req.stdout.flush()

comment:6 by Jun Omae, 4 months ago

Okay. Found how to reproduce it.

  1. Log in with username which has non-ascii characters.
  2. Visit attachment page, as the result, an exception raised

tracd

The same UnicodeEncodeError is raised while sending response headers.

Traceback (most recent call last):
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/main.py", line 609, in dispatch_request
    dispatcher.dispatch(req)
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/main.py", line 301, in dispatch
    raise e
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/main.py", line 266, in dispatch
    req.send(output, content_type or 'text/html')
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/api.py", line 875, in send
    self._send(content, content_type, status)
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/api.py", line 1011, in _send
    self.write(content)
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/api.py", line 977, in write
    self._write(b''.join(buf))
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/wsgi.py", line 259, in _write
    self.handler.send_header(name, value)
  File "/usr/lib/python3.11/http/server.py", line 526, in send_header
    ("%s: %s\r\n" % (keyword, value)).encode('latin-1', 'strict'))
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 9-11: ordinal not in range(256)

mod_wsgi

The mod_wsgi raises ValueError if the response headers have non latin-1 characters.

Traceback (most recent call last):
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/main.py", line 609, in dispatch_request
    dispatcher.dispatch(req)
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/main.py", line 301, in dispatch
    raise e
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/main.py", line 266, in dispatch
    req.send(output, content_type or 'text/html')
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/api.py", line 875, in send
    self._send(content, content_type, status)
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/api.py", line 1008, in _send
    self.end_headers(exc_info)
  File "/venv/trac/1.6/lib/python3.11/site-packages/trac/web/api.py", line 799, in end_headers
    self._write = self._start_response(self._status, self._outheaders,
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: unicode object contains non latin-1 characters

comment:7 by Jun Omae, 11 days ago

Proposed changes in [a7e892a08/jomae.git]. After the changes, only ascii characters for the ETag header are used even if logged in with username contains non-ascii characters.

comment:8 by Jun Omae, 11 days ago

Also, I consider that it might be good to check the status and headers do not contain latin-1 characters in WSGIGateway._start_response like mod_wsgi.

  • trac/web/wsgi.py

    diff --git a/trac/web/wsgi.py b/trac/web/wsgi.py
    index 36f74d329..ec4702f78 100644
    a b  
    1616
    1717from abc import ABCMeta, abstractmethod
    1818import errno
     19import re
    1920import sys
    2021from http.server import HTTPServer, BaseHTTPRequestHandler
    2122from socketserver import ThreadingMixIn
    class WSGIGateway(object, metaclass=ABCMeta):  
    131132
    132133    def _start_response(self, status, headers, exc_info=None):
    133134        """Callback for starting a HTTP response."""
     135        ctrl_re = re.compile(r'[\x00-\x1f\x7f]')
     136
     137        def check_header(item, label):
     138            if not isinstance(item, str):
     139                raise TypeError('Expected str instance in %s' % label)
     140            try:
     141                item.encode('latin-1')
     142            except UnicodeEncodeError:
     143                raise ValueError('Non latin-1 characters are used in %s' %
     144                                 label) from None
     145            if ctrl_re.search(item):
     146                raise ValueError('Control characters are used in %s' % label)
     147
     148        check_header(status, 'status')
     149        for name, value in headers:
     150            check_header(name, 'headers')
     151            check_header(value, 'headers')
     152
    134153        if exc_info:
    135154            try:
    136155                if self.headers_sent: # Re-raise original exception

comment:9 by Jun Omae, 5 days ago

Release Notes: modified (diff)
Resolution: fixed
Status: assignedclosed

Fixed in [17786:17787] and merged in [17788].

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Jun Omae.
The resolution will be deleted. Next status will be 'reopened'.
to The owner will be changed from Jun Omae to the specified user.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.