2017-05-26 08:57:09 +01:00
// Copyright 2017 Vector Creations Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package routing
import (
2021-11-24 12:55:44 +00:00
"encoding/json"
2017-05-26 08:57:09 +01:00
"net/http"
2020-06-16 18:31:38 +01:00
"strings"
2017-05-26 08:57:09 +01:00
"github.com/gorilla/mux"
2020-06-12 14:55:57 +01:00
"github.com/matrix-org/dendrite/internal/httputil"
2017-05-26 15:49:54 +01:00
"github.com/matrix-org/dendrite/mediaapi/storage"
2017-05-26 08:57:09 +01:00
"github.com/matrix-org/dendrite/mediaapi/types"
2020-12-02 17:41:00 +00:00
"github.com/matrix-org/dendrite/setup/config"
2021-11-24 12:55:44 +00:00
userapi "github.com/matrix-org/dendrite/userapi/api"
2017-05-26 08:57:09 +01:00
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util"
"github.com/prometheus/client_golang/prometheus"
2019-12-17 16:47:45 +00:00
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
2017-05-26 08:57:09 +01:00
)
2021-11-24 12:55:44 +00:00
// configResponse is the response to GET /_matrix/media/r0/config
// https://matrix.org/docs/spec/client_server/latest#get-matrix-media-r0-config
type configResponse struct {
UploadSize config . FileSizeBytes ` json:"m.upload.size" `
}
2017-08-03 15:10:39 +01:00
// Setup registers the media API HTTP handlers
2019-07-03 16:38:50 +01:00
//
// Due to Setup being used to call many other functions, a gocyclo nolint is
// applied:
// nolint: gocyclo
2017-09-21 16:20:10 +01:00
func Setup (
2020-05-22 11:43:17 +01:00
publicAPIMux * mux . Router ,
2020-08-10 14:18:04 +01:00
cfg * config . MediaAPI ,
2021-11-24 12:55:44 +00:00
rateLimit * config . RateLimiting ,
2020-01-03 14:07:05 +00:00
db storage . Database ,
2020-06-16 14:10:55 +01:00
userAPI userapi . UserInternalAPI ,
2017-09-21 16:20:10 +01:00
client * gomatrixserverlib . Client ,
) {
2021-11-24 12:55:44 +00:00
rateLimits := httputil . NewRateLimits ( rateLimit )
2020-08-13 12:16:37 +01:00
r0mux := publicAPIMux . PathPrefix ( "/r0" ) . Subrouter ( )
v1mux := publicAPIMux . PathPrefix ( "/v1" ) . Subrouter ( )
2017-06-07 00:12:49 +01:00
activeThumbnailGeneration := & types . ActiveThumbnailGeneration {
PathToResult : map [ string ] * types . ThumbnailGenerationResult { } ,
}
2020-07-08 16:39:50 +01:00
uploadHandler := httputil . MakeAuthAPI (
2020-06-16 14:10:55 +01:00
"upload" , userAPI ,
2020-08-26 15:38:34 +01:00
func ( req * http . Request , dev * userapi . Device ) util . JSONResponse {
2021-11-24 12:55:44 +00:00
if r := rateLimits . Limit ( req ) ; r != nil {
return * r
}
2020-08-26 15:38:34 +01:00
return Upload ( req , cfg , dev , db , activeThumbnailGeneration )
2017-09-28 14:50:40 +01:00
} ,
2020-07-08 16:39:50 +01:00
)
2021-11-24 12:55:44 +00:00
configHandler := httputil . MakeAuthAPI ( "config" , userAPI , func ( req * http . Request , device * userapi . Device ) util . JSONResponse {
if r := rateLimits . Limit ( req ) ; r != nil {
return * r
}
return util . JSONResponse {
Code : http . StatusOK ,
JSON : configResponse { UploadSize : * cfg . MaxFileSizeBytes } ,
}
} )
2020-07-08 16:39:50 +01:00
r0mux . Handle ( "/upload" , uploadHandler ) . Methods ( http . MethodPost , http . MethodOptions )
2021-11-24 12:55:44 +00:00
r0mux . Handle ( "/config" , configHandler ) . Methods ( http . MethodGet , http . MethodOptions )
2020-07-08 16:39:50 +01:00
v1mux . Handle ( "/upload" , uploadHandler ) . Methods ( http . MethodPost , http . MethodOptions )
2017-05-26 08:57:09 +01:00
activeRemoteRequests := & types . ActiveRemoteRequests {
2017-05-31 16:56:11 +01:00
MXCToResult : map [ string ] * types . RemoteRequestResult { } ,
2017-05-26 08:57:09 +01:00
}
2020-06-16 14:29:11 +01:00
2021-11-24 12:55:44 +00:00
downloadHandler := makeDownloadAPI ( "download" , cfg , rateLimits , db , client , activeRemoteRequests , activeThumbnailGeneration )
2020-06-16 14:29:11 +01:00
r0mux . Handle ( "/download/{serverName}/{mediaId}" , downloadHandler ) . Methods ( http . MethodGet , http . MethodOptions )
2020-06-17 11:53:26 +01:00
r0mux . Handle ( "/download/{serverName}/{mediaId}/{downloadName}" , downloadHandler ) . Methods ( http . MethodGet , http . MethodOptions )
v1mux . Handle ( "/download/{serverName}/{mediaId}" , downloadHandler ) . Methods ( http . MethodGet , http . MethodOptions ) // TODO: remove when synapse is fixed
v1mux . Handle ( "/download/{serverName}/{mediaId}/{downloadName}" , downloadHandler ) . Methods ( http . MethodGet , http . MethodOptions ) // TODO: remove when synapse is fixed
2020-06-16 14:29:11 +01:00
2017-06-07 00:12:49 +01:00
r0mux . Handle ( "/thumbnail/{serverName}/{mediaId}" ,
2021-11-24 12:55:44 +00:00
makeDownloadAPI ( "thumbnail" , cfg , rateLimits , db , client , activeRemoteRequests , activeThumbnailGeneration ) ,
2018-03-13 15:55:45 +00:00
) . Methods ( http . MethodGet , http . MethodOptions )
2017-05-26 08:57:09 +01:00
}
2017-06-07 00:12:49 +01:00
2017-09-21 16:20:10 +01:00
func makeDownloadAPI (
name string ,
2020-08-10 14:18:04 +01:00
cfg * config . MediaAPI ,
2021-11-24 12:55:44 +00:00
rateLimits * httputil . RateLimits ,
2020-01-03 14:07:05 +00:00
db storage . Database ,
2017-09-21 16:20:10 +01:00
client * gomatrixserverlib . Client ,
activeRemoteRequests * types . ActiveRemoteRequests ,
activeThumbnailGeneration * types . ActiveThumbnailGeneration ,
) http . HandlerFunc {
2019-12-18 15:10:53 +00:00
counterVec := promauto . NewCounterVec (
prometheus . CounterOpts {
Name : name ,
Help : "Total number of media_api requests for either thumbnails or full downloads" ,
2019-12-17 16:47:45 +00:00
} ,
2019-12-18 15:10:53 +00:00
[ ] string { "code" } ,
)
httpHandler := func ( w http . ResponseWriter , req * http . Request ) {
req = util . RequestWithLogging ( req )
2020-05-21 14:40:13 +01:00
// Set internal headers returned regardless of the outcome of the request
2019-12-18 15:10:53 +00:00
util . SetCORSHeaders ( w )
// Content-Type will be overridden in case of returning file data, else we respond with JSON-formatted errors
w . Header ( ) . Set ( "Content-Type" , "application/json" )
2020-06-16 18:31:38 +01:00
2021-11-24 12:55:44 +00:00
// Ratelimit requests
if r := rateLimits . Limit ( req ) ; r != nil {
if err := json . NewEncoder ( w ) . Encode ( r ) ; err != nil {
w . WriteHeader ( http . StatusInternalServerError )
return
}
w . WriteHeader ( http . StatusTooManyRequests )
return
}
2020-06-12 14:55:57 +01:00
vars , _ := httputil . URLDecodeMapValues ( mux . Vars ( req ) )
2020-06-16 18:31:38 +01:00
serverName := gomatrixserverlib . ServerName ( vars [ "serverName" ] )
// For the purposes of loop avoidance, we will return a 404 if allow_remote is set to
// false in the query string and the target server name isn't our own.
// https://github.com/matrix-org/matrix-doc/pull/1265
if allowRemote := req . URL . Query ( ) . Get ( "allow_remote" ) ; strings . ToLower ( allowRemote ) == "false" {
if serverName != cfg . Matrix . ServerName {
w . WriteHeader ( http . StatusNotFound )
return
}
}
2019-12-18 15:10:53 +00:00
Download (
w ,
req ,
2020-06-16 18:31:38 +01:00
serverName ,
2019-12-18 15:10:53 +00:00
types . MediaID ( vars [ "mediaId" ] ) ,
cfg ,
db ,
client ,
activeRemoteRequests ,
activeThumbnailGeneration ,
name == "thumbnail" ,
2020-06-17 11:53:26 +01:00
vars [ "downloadName" ] ,
2019-12-18 15:10:53 +00:00
)
}
return promhttp . InstrumentHandlerCounter ( counterVec , http . HandlerFunc ( httpHandler ) )
2017-06-07 00:12:49 +01:00
}