view Resources/Samples/Python/ChangesLoop.py @ 2248:69b0f4e8a49b

Escape multipart type parameter value in Content-Type header ## Summary Multipart responses do not quote/escape the value of their type parameter (the subtype) even though it always contains at least one special character (the slash "/"), which confuses standard-compliant HTTP clients. ## Details The Content-Type header in HTTP is in RFC 7231, Section 3.1.1.5: https://tools.ietf.org/html/rfc7231#section-3.1.1.5 The section defers to the media type section (3.1.1.1) for the syntax of the media type: https://tools.ietf.org/html/rfc7231#section-3.1.1.1 This states that a parameter value can be quoted: parameter = token "=" ( token / quoted-string ) A parameter value that matches the token production can be transmitted either as a token or within a quoted-string. The quoted and unquoted values are equivalent. Tokens are defined in RFC 7230, Section 3.2.6 (via RFC 7231, appendix C): https://tools.ietf.org/html/rfc7231#appendix-C https://tools.ietf.org/html/rfc7230#section-3.2.6 Here we observe that tokens cannot contain a slash "/" character: token = 1*tchar tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA ; any VCHAR, except delimiters Delimiters are chosen from the set of US-ASCII visual characters not allowed in a token (DQUOTE and "(),/:;<=>?@[\]{}"). However, the current implementation does not quote/escape the value of the type parameter: multipart/related; type=application/dicom Instead, it should be: multipart/related; type="application/dicom" All of this also seems to apply to the MIME Content-Type header definition, even though it is a little different: https://www.iana.org/assignments/message-headers https://tools.ietf.org/html/rfc2045#section-5.1 https://tools.ietf.org/html/rfc2387
author Thibault Nélis <tn@osimis.io>
date Mon, 16 Jan 2017 13:07:11 +0100
parents a3a65de1840f
children 878b59270859
line wrap: on
line source

#!/usr/bin/python

# Orthanc - A Lightweight, RESTful DICOM Store
# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
# Department, University Hospital of Liege, Belgium
# Copyright (C) 2017 Osimis, Belgium
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.



import time
import sys
import RestToolbox


##
## Print help message
##

if len(sys.argv) != 3:
    print("""
Sample script that continuously monitors the arrival of new DICOM
images into Orthanc (through the Changes API).

Usage: %s [hostname] [HTTP port]
For instance: %s 127.0.0.1 8042
""" % (sys.argv[0], sys.argv[0]))
    exit(-1)

URL = 'http://%s:%d' % (sys.argv[1], int(sys.argv[2]))



##
## The following function is called each time a new instance is
## received.
##

def NewInstanceReceived(path):
    global URL
    patientName = RestToolbox.DoGet(URL + path + '/content/PatientName')
    
    # Remove the possible trailing characters due to DICOM padding
    patientName = patientName.strip()

    print('New instance received for patient "%s": "%s"' % (patientName, path))



##
## Main loop that listens to the changes API.
## 

current = 0
while True:
    r = RestToolbox.DoGet(URL + '/changes', {
            'since' : current,
            'limit' : 4   # Retrieve at most 4 changes at once
            })

    for change in r['Changes']:
        # We are only interested interested in the arrival of new instances
        if change['ChangeType'] == 'NewInstance':
            # Call the callback function
            path = change['Path']
            NewInstanceReceived(path)

            # Delete the instance once it has been discovered
            RestToolbox.DoDelete(URL + path)

    current = r['Last']

    if r['Done']:
        print('Everything has been processed: Waiting...')
        time.sleep(1)