Flesh out content repo; modify templating to support headers

Edit content-repo.yaml to include examples and headers.
Restructure content module to conform to the module template.
Adjust the HTTP API template to give 1 more char to the response
param to fit "Content-Disposition" correctly.
Edit the templating system to support displaying enums for
swagger APIs (before it was just JSON schema). Also add support
for introspecting headers from swagger. Finally, replace - with
_ when forming the {{ template_var }} else things whine.
This commit is contained in:
Kegan Dougal 2015-10-01 17:55:16 +01:00
parent 4a7a682c0f
commit 87b6dd845e
4 changed files with 96 additions and 17 deletions

View file

@ -15,16 +15,22 @@ paths:
summary: Upload some content to the content repository. summary: Upload some content to the content repository.
produces: ["application/json"] produces: ["application/json"]
parameters: parameters:
- in: header
name: Content-Type
type: string
description: The content type of the file being uploaded
x-example: "Content-Type: audio/mpeg"
- in: body - in: body
name: content name: "<content>"
description: The content to be uploaded. description: The content to be uploaded.
required: true required: true
schema: schema:
type: string type: string
example: "<bytes>"
format: byte format: byte
responses: responses:
200: 200:
description: Information about the uploaded content. description: The MXC URI for the uploaded content.
schema: schema:
type: object type: object
required: ["content_uri"] required: ["content_uri"]
@ -32,6 +38,11 @@ paths:
content_uri: content_uri:
type: string type: string
description: "The MXC URI to the uploaded content." description: "The MXC URI to the uploaded content."
examples:
"application/json": |-
{
"content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw"
}
"/download/{serverName}/{mediaId}": "/download/{serverName}/{mediaId}":
get: get:
summary: "Download content from the content repository." summary: "Download content from the content repository."
@ -40,20 +51,32 @@ paths:
- in: path - in: path
type: string type: string
name: serverName name: serverName
x-example: matrix.org
required: true required: true
description: | description: |
The server name from the ``mxc://`` URI (the authoritory component) The server name from the ``mxc://`` URI (the authoritory component)
- in: path - in: path
type: string type: string
name: mediaId name: mediaId
x-example: ascERGshawAWawugaAcauga
required: true required: true
description: | description: |
The media ID from the ``mxc://`` URI (the path component) The media ID from the ``mxc://`` URI (the path component)
responses: responses:
200: 200:
description: "The content downloaded." description: "The content that was previously uploaded."
headers:
Content-Type:
description: "The content type of the file that was previously uploaded."
x-example: "audio/mpeg"
type: "string"
Content-Disposition:
description: "The name of the file that was previously uploaded, if set."
x-example: "attachment;filename=03-cool.mp3"
type: "string"
schema: schema:
type: file type: file
name: "<file>"
"/thumbnail/{serverName}/{mediaId}": "/thumbnail/{serverName}/{mediaId}":
get: get:
summary: "Download a thumbnail of the content from the content repository." summary: "Download a thumbnail of the content from the content repository."
@ -63,31 +86,47 @@ paths:
type: string type: string
name: serverName name: serverName
required: true required: true
x-example: matrix.org
description: | description: |
The server name from the ``mxc://`` URI (the authoritory component) The server name from the ``mxc://`` URI (the authoritory component)
- in: path - in: path
type: string type: string
name: mediaId name: mediaId
x-example: ascERGshawAWawugaAcauga
required: true required: true
description: | description: |
The media ID from the ``mxc://`` URI (the path component) The media ID from the ``mxc://`` URI (the path component)
- in: query - in: query
type: integer type: integer
x-example: 64
name: width name: width
description: The desired width of the thumbnail. description: |-
The *desired* width of the thumbnail. The actual thumbnail may not
match the size specified.
- in: query - in: query
type: integer type: integer
x-example: 64
name: height name: height
description: The desired height of the thumbnail. description: |-
The *desired* height of the thumbnail. The actual thumbnail may not
match the size specified.
- in: query - in: query
type: string type: string
enum: ["crop", "scale"] enum: ["crop", "scale"]
name: method name: method
x-example: "scale"
description: The desired resizing method. description: The desired resizing method.
responses: responses:
200: 200:
description: "A thumbnail of the requested content." description: "A thumbnail of the requested content."
headers:
Content-Type:
description: "The content type of the thumbnail."
x-example: "image/jpeg"
type: "string"
enum: ["image/jpeg", "image/png"]
schema: schema:
type: file type: file
name: "<file>"

View file

@ -3,8 +3,23 @@ Content repository
.. _module:content: .. _module:content:
HTTP API This module allows users to upload content to their homeserver which is
-------- retrievable from other homeservers. Its' purpose is to allow users to share
attachments in a room. Content locations are represented as Matrix Content (MXC)
URIs. They look like::
mxc://<server-name>/<media-id>
<server-name> : The name of the homeserver where this content can be found, e.g. matrix.org
<media-id> : An opaque ID which identifies the content.
Client behaviour
----------------
Clients can upload and download content using the following HTTP APIs.
{{content_repo_http_api}}
Uploads are POSTed to a resource which returns a token which is used to GET Uploads are POSTed to a resource which returns a token which is used to GET
the download. Uploads are POSTed to the sender's local homeserver, but are the download. Uploads are POSTed to the sender's local homeserver, but are
@ -49,6 +64,9 @@ width and height are close to the requested size and the aspect matches
the requested size. The client should scale the image if it needs to fit the requested size. The client should scale the image if it needs to fit
within a given rectangle. within a given rectangle.
Server behaviour
----------------
Homeservers may generate thumbnails for content uploaded to remote Homeservers may generate thumbnails for content uploaded to remote
homeservers themselves or may rely on the remote homeserver to thumbnail homeservers themselves or may rely on the remote homeserver to thumbnail
the content. Homeservers may return thumbnails of a different size to that the content. Homeservers may return thumbnails of a different size to that
@ -58,13 +76,19 @@ Homeservers must never upscale images.
Security considerations Security considerations
----------------------- -----------------------
The HTTP GET endpoint does not require any authentication. Knowing the URL of
the content is sufficient to retrieve the content, even if the entity isn't in
the room.
Homeservers have additional concerns:
- Clients may try to upload very large files. Homeservers should not store files - Clients may try to upload very large files. Homeservers should not store files
that are too large and should not serve them to clients. that are too large and should not serve them to clients.
- Clients may try to upload very large images. Homeservers should not attempt to - Clients may try to upload very large images. Homeservers should not attempt to
generate thumbnails for images that are too large. generate thumbnails for images that are too large.
- Remote homeservers may host very large files or images. Homeserver should not - Remote homeservers may host very large files or images. Homeservers should not
proxy or thumbnail large files or images from remote homeservers. proxy or thumbnail large files or images from remote homeservers.
- Clients may try to upload a large number of files. Homeservers should limit the - Clients may try to upload a large number of files. Homeservers should limit the

View file

@ -31,18 +31,18 @@ Response format:
{% for table in endpoint.res_tables -%} {% for table in endpoint.res_tables -%}
{{"``"+table.title+"``" if table.title else "" }} {{"``"+table.title+"``" if table.title else "" }}
================== ================= =========================================== =================== ================= ==========================================
Param Type Description Param Type Description
================== ================= =========================================== =================== ================= ==========================================
{% for row in table.rows -%} {% for row in table.rows -%}
{# -#} {# -#}
{# Row type needs to prepend spaces to line up with the type column (19 ch) -#} {# Row type needs to prepend spaces to line up with the type column (20 ch) -#}
{# Desc needs to prepend the required text (maybe) and prepend spaces too -#} {# Desc needs to prepend the required text (maybe) and prepend spaces too -#}
{# It also needs to then wrap inside the desc col (43 ch width) -#} {# It also needs to then wrap inside the desc col (42 ch width) -#}
{# -#} {# -#}
{{row.key}}{{row.type|indent(19-row.key|length)}}{{row.desc|wrap(43,row.req_str | indent(18 - (row.type|length))) |indent_block(37)}} {{row.key}}{{row.type|indent(20-row.key|length)}}{{row.desc|wrap(42,row.req_str | indent(18 - (row.type|length))) |indent_block(38)}}
{% endfor -%} {% endfor -%}
================== ================= =========================================== =================== ================= ==========================================
{% endfor %} {% endfor %}
{% endif -%} {% endif -%}

View file

@ -151,6 +151,13 @@ class MatrixUnits(Units):
# assign value expected for this param # assign value expected for this param
val_type = param.get("type") # integer/string val_type = param.get("type") # integer/string
if param.get("enum"):
val_type = "enum"
desc += (
" One of: %s" % json.dumps(param.get("enum"))
)
refType = Units.prop(param, "schema/$ref/") # Error,Event refType = Units.prop(param, "schema/$ref/") # Error,Event
schemaFmt = Units.prop(param, "schema/format") # bytes e.g. uploads schemaFmt = Units.prop(param, "schema/format") # bytes e.g. uploads
if not val_type and refType: if not val_type and refType:
@ -255,7 +262,7 @@ class MatrixUnits(Units):
res_type = Units.prop(good_response, "schema/type") res_type = Units.prop(good_response, "schema/type")
if res_type and res_type not in ["object", "array"]: if res_type and res_type not in ["object", "array"]:
# response is a raw string or something like that # response is a raw string or something like that
endpoint["res_tables"].append({ good_table = {
"title": None, "title": None,
"rows": [{ "rows": [{
"key": good_response["schema"].get("name", ""), "key": good_response["schema"].get("name", ""),
@ -263,7 +270,16 @@ class MatrixUnits(Units):
"desc": res.get("description", ""), "desc": res.get("description", ""),
"req_str": "" "req_str": ""
}] }]
}) }
if good_response.get("headers"):
for (header_name, header) in good_response.get("headers").iteritems():
good_table["rows"].append({
"key": header_name,
"type": "Header<" + header["type"] + ">",
"desc": header["description"],
"req_str": ""
})
endpoint["res_tables"].append(good_table)
elif res_type and Units.prop(good_response, "schema/properties"): elif res_type and Units.prop(good_response, "schema/properties"):
# response is an object: # response is an object:
schema = good_response["schema"] schema = good_response["schema"]
@ -328,7 +344,7 @@ class MatrixUnits(Units):
self.log("Reading swagger API: %s" % filename) self.log("Reading swagger API: %s" % filename)
with open(os.path.join(path, filename), "r") as f: with open(os.path.join(path, filename), "r") as f:
# strip .yaml # strip .yaml
group_name = filename[:-5] group_name = filename[:-5].replace("-", "_")
api = yaml.load(f.read()) api = yaml.load(f.read())
api["__meta"] = self._load_swagger_meta(api, group_name) api["__meta"] = self._load_swagger_meta(api, group_name)
apis[group_name] = api apis[group_name] = api