3
=^@!                 @   s  d Z ddlmZ ddlZddlmZ ddlmZ ddlm	Z	 ddl
mZ ddl
mZ dd	l
mZmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ G dd deZ G dd deZ!G dd de!Z"G dd de!Z#G dd de!ZG dd de!Z$dS )z
Parsers are used to parse the content of incoming HTTP requests.

They give us a generic way of being able to handle various media types
on the request, such as form content or json encoded data.
    )unicode_literalsN)settings)StopFutureHandlers)	QueryDict)	ChunkIter)MultiPartParser)MultiPartParserErrorparse_header)six)
force_text)parse)	renderers)
ParseError)api_settings)jsonc               @   s   e Zd Zdd ZdS )DataAndFilesc             C   s   || _ || _d S )N)datafiles)selfr   r    r   E/tmp/pip-build-8app2_gc/djangorestframework/rest_framework/parsers.py__init__   s    zDataAndFiles.__init__N)__name__
__module____qualname__r   r   r   r   r   r      s   r   c               @   s   e Zd ZdZdZdddZdS )
BaseParserz
    All parsers should extend `BaseParser`, specifying a `media_type`
    attribute, and overriding the `.parse()` method.
    Nc             C   s   t ddS )z
        Given a stream to read from, return the parsed representation.
        Should return parsed data, or a `DataAndFiles` object consisting of the
        parsed data and files.
        z.parse() must be overridden.N)NotImplementedError)r   stream
media_typeparser_contextr   r   r   r   )   s    zBaseParser.parse)NN)r   r   r   __doc__r   r   r   r   r   r   r   "   s   r   c               @   s*   e Zd ZdZdZejZej	Z
dddZdS )
JSONParserz&
    Parses JSON-serialized data.
    zapplication/jsonNc             C   s|   |pi }|j dtj}y,tj||}| jr2tjnd}tj||dS  t	k
rv } zt
dtj| W Y dd}~X nX dS )zX
        Parses the incoming bytestream as JSON and returns the resulting data.
        encodingN)parse_constantzJSON parse error - %s)getr   DEFAULT_CHARSETcodecs	getreaderstrictr   Zstrict_constantload
ValueErrorr   r
   	text_type)r   r   r   r   r"   Zdecoded_streamr#   excr   r   r   r   :   s    zJSONParser.parse)NN)r   r   r   r    r   r   ZJSONRendererZrenderer_classr   ZSTRICT_JSONr(   r   r   r   r   r   r!   2   s
   r!   c               @   s   e Zd ZdZdZdddZdS )
FormParserz
    Parser for form data.
    z!application/x-www-form-urlencodedNc             C   s*   |pi }|j dtj}t|j |d}|S )zt
        Parses the incoming bytestream as a URL encoded form,
        and returns the resulting QueryDict.
        r"   )r"   )r$   r   r%   r   read)r   r   r   r   r"   r   r   r   r   r   O   s    zFormParser.parse)NN)r   r   r   r    r   r   r   r   r   r   r-   I   s   r-   c               @   s   e Zd ZdZdZdddZdS )r   zF
    Parser for multipart form data, which may include file data.
    zmultipart/form-dataNc             C   s   |pi }|d }|j dtj}|jj }||d< |j}y$t||||}|j \}	}
t|	|
S  t	k
r } zt
dtj| W Y dd}~X nX dS )a	  
        Parses the incoming bytestream as a multipart encoded form,
        and returns a DataAndFiles object.

        `.data` will be a `QueryDict` containing all the form parameters.
        `.files` will be a `QueryDict` containing all the form files.
        requestr"   CONTENT_TYPEzMultipart form parse error - %sN)r$   r   r%   METAcopyupload_handlersDjangoMultiPartParserr   r   r   r   r
   r+   )r   r   r   r   r/   r"   metar3   parserr   r   r,   r   r   r   r   `   s    

zMultiPartParser.parse)NN)r   r   r   r    r   r   r   r   r   r   r   Z   s   r   c               @   s8   e Zd ZdZdZdddZdddZd	d
 Zdd ZdS )FileUploadParserz&
    Parser for file upload data.
    z*/*zFFileUpload parse error - none of upload handlers can handle the streamz`Missing filename. Request should include a Content-Disposition header with a filename parameter.)	unhandledno_filenameNc             C   s
  |pi }|d }|j dtj}|j}|j}| j|||}|sJt| jd |j d|j dd}	yt|j d|j dd	}
W n t	t
fk
r   d
}
Y nX x8|D ]0}|j|||
d
|}|d
k	rti d|d iS qW dd |D }tdg| }t||}d	gt| }xVt|D ]J\}}y|jd
||	|
| W n( tk
rV   |d
|d  }P Y nX qW xZ|D ]R}xJt|D ]>\}}t|}|j||| }||  |7  < |d
krrP qrW qdW x<t|D ]0\}}|j|| }|d
k	rti d|iS qW t| jd d
S )a  
        Treats the incoming bytestream as a raw file upload and returns
        a `DataAndFiles` object.

        `.data` will be None (we expect request body to be a file content).
        `.files` will be a `QueryDict` containing one 'file' element.
        r/   r"   r9   ZHTTP_CONTENT_TYPEr0    ZHTTP_CONTENT_LENGTHCONTENT_LENGTHr   Nfile   c             S   s   g | ]}|j r|j qS r   )
chunk_size).0xr   r   r   
<listcomp>   s    z*FileUploadParser.parse.<locals>.<listcomp>         r8   l        i)r$   r   r%   r1   r3   get_filenamer   errorsintr*   	TypeErrorZhandle_raw_inputr   minr   len	enumerateZnew_filer   Zreceive_data_chunkZfile_complete)r   r   r   r   r/   r"   r5   r3   filenamecontent_typecontent_lengthhandlerresultZpossible_sizesr>   chunksZcountersindexchunkZchunk_lengthZfile_objr   r   r   r      s\    






zFileUploadParser.parsec             C   s   y|d d S  t k
r    Y nX yB|d j}t|d jd}|d }d|krZ| j|S t|d S  tt tfk
r~   Y nX dS )	z
        Detects the uploaded file name. First searches a 'filename' url kwarg.
        Then tries to parse Content-Disposition header.
        kwargsrL   r/   ZHTTP_CONTENT_DISPOSITIONzutf-8r=   z	filename*N)KeyErrorr1   r	   encodeget_encoded_filenamer   AttributeErrorr*   )r   r   r   r   r5   dispositionfilename_parmr   r   r   rE      s    

zFileUploadParser.get_filenamec             C   sV   t |d }y |jdd\}}}tj|}W n$ ttfk
rP   t |d }Y nX |S )zw
        Handle encoded filenames per RFC6266. See also:
        https://tools.ietf.org/html/rfc2231#section-4
        z	filename*'rB   rL   )r   spliturlparseunquoter*   LookupError)r   rZ   Zencoded_filenamecharsetlangrL   r   r   r   rW      s    z%FileUploadParser.get_encoded_filename)NN)	r   r   r   r    r   rF   r   rE   rW   r   r   r   r   r7   w   s   
Cr7   )%r    
__future__r   r&   Zdjango.confr   Zdjango.core.files.uploadhandlerr   Zdjango.httpr   Zdjango.http.multipartparserr   r   r4   r   r	   Zdjango.utilsr
   Zdjango.utils.encodingr   Zdjango.utils.six.moves.urllibr   r]   Zrest_frameworkr   Zrest_framework.exceptionsr   Zrest_framework.settingsr   Zrest_framework.utilsr   objectr   r   r!   r-   r7   r   r   r   r   <module>   s*   