3085: 'Server' configuration setting is not used for absolute URIs in webapi

stuar******@gmai***** (Google Code) (Is this you? Claim this profile.)
david
david
Feb. 18, 2014
3119
What version are you running?

1.7.13

What's the URL of the page containing the problem?

Going from Draft report https://example.com/reviews/r/1234/ -> Publish report

What steps will reproduce the problem?

1. I have a SSL-stripping load balancer, which answers for example.com on port 443. It talks to a web server called web1.example.com on port 80. No other devices can connect to port 80. A web browser can only visit https://example.com/. If it visits http://example.com/ it will get a "Connection Refused"

2. The ReviewBoard site is configured to appear under /reviews/ and System Settings -> General Settings -> Server is set to "https://example.com/"

3. Create a draft review, e.g. https://example.com/reviews/r/54/ and fill in enough to publish.

4. Try to publish. The javascript on the page fetches https://example.com/reviews/api/review-requests/54/?api_format=json which has a "links" section with the absolute URIs for other actions. These links are wrong - they are "http://" instead of "https://", so they fail to load, and no review can be published.

What is the expected output? What do you see instead?

Expected output from https://example.com/reviews/api/review-requests/54/

<?xml version="1.0" encoding="utf-8"?>
<rsp>
 <stat>ok</stat>
 <review_request>
  <status>pending</status>
  <blocks>
   <array>
   </array>
  </blocks>
  <description>test</description>
  <links>
   <diffs>
    <href>https://example.com/reviews/api/review-requests/54/diffs/</href>
    <method>GET</method>
   </diffs>
   <repository>
    <href>https://example.com/reviews/api/repositories/1/</href>
    <method>GET</method>
    <title>Example</title>
   </repository>
   <screenshots>
    <href>https://example.com/reviews/api/review-requests/54/screenshots/</href>
    <method>GET</method>
   </screenshots>
   <self>
    <href>https://example.com/reviews/api/review-requests/54/</href>
    <method>GET</method>
   </self>
   <update>
    <href>https://example.com/reviews/api/review-requests/54/</href>
    <method>PUT</method>
   </update>
   <last_update>
    <href>https://example.com/reviews/api/review-requests/54/last-update/</href>
    <method>GET</method>
   </last_update>
   <reviews>
    <href>https://example.com/reviews/api/review-requests/54/reviews/</href>
    <method>GET</method>
   </reviews>
   <draft>
    <href>https://example.com/reviews/api/review-requests/54/draft/</href>
    <method>GET</method>
   </draft>
   <file_attachments>
    <href>https://example.com/reviews/api/review-requests/54/file-attachments/</href>
    <method>GET</method>
   </file_attachments>
   <submitter>
    <href>https://example.com/reviews/api/users/example.submitter/</href>
    <method>GET</method>
    <title>example.submitter</title>
   </submitter>
   <changes>
    <href>https://example.com/reviews/api/review-requests/54/changes/</href>
    <method>GET</method>
   </changes>
   <delete>
    <href>https://example.com/reviews/api/review-requests/54/</href>
    <method>DELETE</method>
   </delete>
  </links>
  <url>/reviews/r/54/</url>
  <depends_on>
   <array>
   </array>
  </depends_on>
  <target_groups>
   <array>
   </array>
  </target_groups>
  <bugs_closed>
   <array>
   </array>
  </bugs_closed>
  <changenum>
  </changenum>
  <target_people>
   <array>
    <item>
     <href>https://example.com/reviews/api/users/example.person/</href>
     <method>GET</method>
     <title>example.person</title>
    </item>
   </array>
  </target_people>
  <testing_done></testing_done>
  <branch></branch>
  <id>54</id>
  <last_updated>2013-09-09T10:21:24Z</last_updated>
  <time_added>2013-09-09T10:21:24Z</time_added>
  <summary>test</summary>
  <public>1</public>
 </review_request>
</rsp>

Actual output from https://example.com/reviews/api/review-requests/54/

<?xml version="1.0" encoding="utf-8"?>
<rsp>
 <stat>ok</stat>
 <review_request>
  <status>pending</status>
  <blocks>
   <array>
   </array>
  </blocks>
  <description>test</description>
  <links>
   <diffs>
    <href>http://example.com/reviews/api/review-requests/54/diffs/</href>
    <method>GET</method>
   </diffs>
   <repository>
    <href>http://example.com/reviews/api/repositories/1/</href>
    <method>GET</method>
    <title>Example</title>
   </repository>
   <screenshots>
    <href>http://example.com/reviews/api/review-requests/54/screenshots/</href>
    <method>GET</method>
   </screenshots>
   <self>
    <href>http://example.com/reviews/api/review-requests/54/</href>
    <method>GET</method>
   </self>
   <update>
    <href>http://example.com/reviews/api/review-requests/54/</href>
    <method>PUT</method>
   </update>
   <last_update>
    <href>http://example.com/reviews/api/review-requests/54/last-update/</href>
    <method>GET</method>
   </last_update>
   <reviews>
    <href>http://example.com/reviews/api/review-requests/54/reviews/</href>
    <method>GET</method>
   </reviews>
   <draft>
    <href>http://example.com/reviews/api/review-requests/54/draft/</href>
    <method>GET</method>
   </draft>
   <file_attachments>
    <href>http://example.com/reviews/api/review-requests/54/file-attachments/</href>
    <method>GET</method>
   </file_attachments>
   <submitter>
    <href>http://example.com/reviews/api/users/example.submitter/</href>
    <method>GET</method>
    <title>example.submitter</title>
   </submitter>
   <changes>
    <href>http://example.com/reviews/api/review-requests/54/changes/</href>
    <method>GET</method>
   </changes>
   <delete>
    <href>http://example.com/reviews/api/review-requests/54/</href>
    <method>DELETE</method>
   </delete>
  </links>
  <url>/reviews/r/54/</url>
  <depends_on>
   <array>
   </array>
  </depends_on>
  <target_groups>
   <array>
   </array>
  </target_groups>
  <bugs_closed>
   <array>
   </array>
  </bugs_closed>
  <changenum>
  </changenum>
  <target_people>
   <array>
    <item>
     <href>http://example.com/reviews/api/users/example.person/</href>
     <method>GET</method>
     <title>example.person</title>
    </item>
   </array>
  </target_people>
  <testing_done></testing_done>
  <branch></branch>
  <id>54</id>
  <last_updated>2013-09-09T10:21:24Z</last_updated>
  <time_added>2013-09-09T10:21:24Z</time_added>
  <summary>test</summary>
  <public>1</public>
 </review_request>
</rsp>


What operating system are you using? What browser?

RHEL 5.8 with:
- Python 2.6 from EPEL5:
--- python26 2.6.8
--- python26-devel 2.6.8
--- python26-distribute 0.6.10
--- python26-mysqldb 1.2.3
- Python packages installed with easy_install
--- Django 1.4.6
--- django_evolution 0.6.9
--- django_pipeline 1.2.24
--- Djblets 0.7.17
--- docutils 0.11
--- feedparser 5.1.3
--- Markdown 2.3.1
--- mimeparse 0.1.3
--- paramiko 1.11.0
--- PIL 1.1.6
--- pycrypto 2.6
--- Pygments 1.6
--- python_dateutil 1.5
--- python_memcached 1.53
--- pytz 2013d
--- recaptcha_client 1.0.6
--- ReviewBoard 1.7.13

Firefox 23.0

Please provide any additional information below.

The reason this happens is because absolute URI configured in ReviewBoard's configuration section isn't used, and instead Django is left to build the absolute URI.

The <links> section is created by djblets.webapi.resources.WebAPIResource.get_links which then calls get_href on each resource.

All the get_href implementations, whether the djblets implementation or overridden by ReviewBoard.webapi.resources.*, make this type of call:

        return request.build_absolute_uri(
            reverse(self._build_named_url(self.name), kwargs=href_kwargs))

"reverse(....)" returns a relative URI, e.g. "/reviews/r/54/".

"request" is a django.http.HttpRequest, and its build_absolute_uri is not overridden. The behaviour of Django is documented at https://docs.djangoproject.com/en/1.4/ref/settings/#secure-proxy-ssl-header - Django makes a guess at the absolute URI based on Apache environment headers, and because my server is configured so Apache is serving plain HTTP, it guesses the address is "http://example.com/", not the correct "https://example.com/".

Ultimately I solved my problem by setting the Django-specific configuration mentioned in the link above. But I wish I didn't have to. It's my expectation that ReviewBoard, which has a mandatory configuration item for the absolute URI of the web server, should _use_ that configured absolute URI in all areas and _should not_ leave it to Django to guess.
david
#2 david
  • +Component-API
david
#3 david
  • +PendingReview
  • +david
david
#4 david
Fixed in release-1.7.x (ac6f869). Thanks!
  • -PendingReview
    +Fixed