package inthttp import ( "context" "errors" "fmt" "net/http" asAPI "github.com/matrix-org/dendrite/appservice/api" fsInputAPI "github.com/matrix-org/dendrite/federationapi/api" "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/roomserver/api" userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib" "github.com/opentracing/opentracing-go" ) const ( // Alias operations RoomserverSetRoomAliasPath = "/roomserver/setRoomAlias" RoomserverGetRoomIDForAliasPath = "/roomserver/GetRoomIDForAlias" RoomserverGetAliasesForRoomIDPath = "/roomserver/GetAliasesForRoomID" RoomserverGetCreatorIDForAliasPath = "/roomserver/GetCreatorIDForAlias" RoomserverRemoveRoomAliasPath = "/roomserver/removeRoomAlias" // Input operations RoomserverInputRoomEventsPath = "/roomserver/inputRoomEvents" // Perform operations RoomserverPerformInvitePath = "/roomserver/performInvite" RoomserverPerformPeekPath = "/roomserver/performPeek" RoomserverPerformUnpeekPath = "/roomserver/performUnpeek" RoomserverPerformRoomUpgradePath = "/roomserver/performRoomUpgrade" RoomserverPerformJoinPath = "/roomserver/performJoin" RoomserverPerformLeavePath = "/roomserver/performLeave" RoomserverPerformBackfillPath = "/roomserver/performBackfill" RoomserverPerformPublishPath = "/roomserver/performPublish" RoomserverPerformInboundPeekPath = "/roomserver/performInboundPeek" RoomserverPerformForgetPath = "/roomserver/performForget" // Query operations RoomserverQueryLatestEventsAndStatePath = "/roomserver/queryLatestEventsAndState" RoomserverQueryStateAfterEventsPath = "/roomserver/queryStateAfterEvents" RoomserverQueryEventsByIDPath = "/roomserver/queryEventsByID" RoomserverQueryMembershipForUserPath = "/roomserver/queryMembershipForUser" RoomserverQueryMembershipsForRoomPath = "/roomserver/queryMembershipsForRoom" RoomserverQueryServerJoinedToRoomPath = "/roomserver/queryServerJoinedToRoomPath" RoomserverQueryServerAllowedToSeeEventPath = "/roomserver/queryServerAllowedToSeeEvent" RoomserverQueryMissingEventsPath = "/roomserver/queryMissingEvents" RoomserverQueryStateAndAuthChainPath = "/roomserver/queryStateAndAuthChain" RoomserverQueryRoomVersionCapabilitiesPath = "/roomserver/queryRoomVersionCapabilities" RoomserverQueryRoomVersionForRoomPath = "/roomserver/queryRoomVersionForRoom" RoomserverQueryPublishedRoomsPath = "/roomserver/queryPublishedRooms" RoomserverQueryCurrentStatePath = "/roomserver/queryCurrentState" RoomserverQueryRoomsForUserPath = "/roomserver/queryRoomsForUser" RoomserverQueryBulkStateContentPath = "/roomserver/queryBulkStateContent" RoomserverQuerySharedUsersPath = "/roomserver/querySharedUsers" RoomserverQueryKnownUsersPath = "/roomserver/queryKnownUsers" RoomserverQueryServerBannedFromRoomPath = "/roomserver/queryServerBannedFromRoom" RoomserverQueryAuthChainPath = "/roomserver/queryAuthChain" ) type httpRoomserverInternalAPI struct { roomserverURL string httpClient *http.Client cache caching.RoomVersionCache } // NewRoomserverClient creates a RoomserverInputAPI implemented by talking to a HTTP POST API. // If httpClient is nil an error is returned func NewRoomserverClient( roomserverURL string, httpClient *http.Client, cache caching.RoomVersionCache, ) (api.RoomserverInternalAPI, error) { if httpClient == nil { return nil, errors.New("NewRoomserverInternalAPIHTTP: httpClient is ") } return &httpRoomserverInternalAPI{ roomserverURL: roomserverURL, httpClient: httpClient, cache: cache, }, nil } // SetFederationInputAPI no-ops in HTTP client mode as there is no chicken/egg scenario func (h *httpRoomserverInternalAPI) SetFederationAPI(fsAPI fsInputAPI.FederationInternalAPI, keyRing *gomatrixserverlib.KeyRing) { } // SetAppserviceAPI no-ops in HTTP client mode as there is no chicken/egg scenario func (h *httpRoomserverInternalAPI) SetAppserviceAPI(asAPI asAPI.AppServiceQueryAPI) { } // SetUserAPI no-ops in HTTP client mode as there is no chicken/egg scenario func (h *httpRoomserverInternalAPI) SetUserAPI(userAPI userapi.UserInternalAPI) { } // SetRoomAlias implements RoomserverAliasAPI func (h *httpRoomserverInternalAPI) SetRoomAlias( ctx context.Context, request *api.SetRoomAliasRequest, response *api.SetRoomAliasResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "SetRoomAlias") defer span.Finish() apiURL := h.roomserverURL + RoomserverSetRoomAliasPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // GetRoomIDForAlias implements RoomserverAliasAPI func (h *httpRoomserverInternalAPI) GetRoomIDForAlias( ctx context.Context, request *api.GetRoomIDForAliasRequest, response *api.GetRoomIDForAliasResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "GetRoomIDForAlias") defer span.Finish() apiURL := h.roomserverURL + RoomserverGetRoomIDForAliasPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // GetAliasesForRoomID implements RoomserverAliasAPI func (h *httpRoomserverInternalAPI) GetAliasesForRoomID( ctx context.Context, request *api.GetAliasesForRoomIDRequest, response *api.GetAliasesForRoomIDResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "GetAliasesForRoomID") defer span.Finish() apiURL := h.roomserverURL + RoomserverGetAliasesForRoomIDPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // GetCreatorIDForAlias implements RoomserverAliasAPI func (h *httpRoomserverInternalAPI) GetCreatorIDForAlias( ctx context.Context, request *api.GetCreatorIDForAliasRequest, response *api.GetCreatorIDForAliasResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "GetCreatorIDForAlias") defer span.Finish() apiURL := h.roomserverURL + RoomserverGetCreatorIDForAliasPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // RemoveRoomAlias implements RoomserverAliasAPI func (h *httpRoomserverInternalAPI) RemoveRoomAlias( ctx context.Context, request *api.RemoveRoomAliasRequest, response *api.RemoveRoomAliasResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "RemoveRoomAlias") defer span.Finish() apiURL := h.roomserverURL + RoomserverRemoveRoomAliasPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // InputRoomEvents implements RoomserverInputAPI func (h *httpRoomserverInternalAPI) InputRoomEvents( ctx context.Context, request *api.InputRoomEventsRequest, response *api.InputRoomEventsResponse, ) { span, ctx := opentracing.StartSpanFromContext(ctx, "InputRoomEvents") defer span.Finish() apiURL := h.roomserverURL + RoomserverInputRoomEventsPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) if err != nil { response.ErrMsg = err.Error() } } func (h *httpRoomserverInternalAPI) PerformInvite( ctx context.Context, request *api.PerformInviteRequest, response *api.PerformInviteResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "PerformInvite") defer span.Finish() apiURL := h.roomserverURL + RoomserverPerformInvitePath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } func (h *httpRoomserverInternalAPI) PerformJoin( ctx context.Context, request *api.PerformJoinRequest, response *api.PerformJoinResponse, ) { span, ctx := opentracing.StartSpanFromContext(ctx, "PerformJoin") defer span.Finish() apiURL := h.roomserverURL + RoomserverPerformJoinPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) if err != nil { response.Error = &api.PerformError{ Msg: fmt.Sprintf("failed to communicate with roomserver: %s", err), } } } func (h *httpRoomserverInternalAPI) PerformPeek( ctx context.Context, request *api.PerformPeekRequest, response *api.PerformPeekResponse, ) { span, ctx := opentracing.StartSpanFromContext(ctx, "PerformPeek") defer span.Finish() apiURL := h.roomserverURL + RoomserverPerformPeekPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) if err != nil { response.Error = &api.PerformError{ Msg: fmt.Sprintf("failed to communicate with roomserver: %s", err), } } } func (h *httpRoomserverInternalAPI) PerformInboundPeek( ctx context.Context, request *api.PerformInboundPeekRequest, response *api.PerformInboundPeekResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "PerformInboundPeek") defer span.Finish() apiURL := h.roomserverURL + RoomserverPerformInboundPeekPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } func (h *httpRoomserverInternalAPI) PerformUnpeek( ctx context.Context, request *api.PerformUnpeekRequest, response *api.PerformUnpeekResponse, ) { span, ctx := opentracing.StartSpanFromContext(ctx, "PerformUnpeek") defer span.Finish() apiURL := h.roomserverURL + RoomserverPerformUnpeekPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) if err != nil { response.Error = &api.PerformError{ Msg: fmt.Sprintf("failed to communicate with roomserver: %s", err), } } } func (h *httpRoomserverInternalAPI) PerformRoomUpgrade( ctx context.Context, request *api.PerformRoomUpgradeRequest, response *api.PerformRoomUpgradeResponse, ) { span, ctx := opentracing.StartSpanFromContext(ctx, "PerformRoomUpgrade") defer span.Finish() apiURL := h.roomserverURL + RoomserverPerformRoomUpgradePath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) if err != nil { response.Error = &api.PerformError{ Msg: fmt.Sprintf("failed to communicate with roomserver: %s", err), } } } func (h *httpRoomserverInternalAPI) PerformLeave( ctx context.Context, request *api.PerformLeaveRequest, response *api.PerformLeaveResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "PerformLeave") defer span.Finish() apiURL := h.roomserverURL + RoomserverPerformLeavePath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } func (h *httpRoomserverInternalAPI) PerformPublish( ctx context.Context, req *api.PerformPublishRequest, res *api.PerformPublishResponse, ) { span, ctx := opentracing.StartSpanFromContext(ctx, "PerformPublish") defer span.Finish() apiURL := h.roomserverURL + RoomserverPerformPublishPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res) if err != nil { res.Error = &api.PerformError{ Msg: fmt.Sprintf("failed to communicate with roomserver: %s", err), } } } // QueryLatestEventsAndState implements RoomserverQueryAPI func (h *httpRoomserverInternalAPI) QueryLatestEventsAndState( ctx context.Context, request *api.QueryLatestEventsAndStateRequest, response *api.QueryLatestEventsAndStateResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryLatestEventsAndState") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryLatestEventsAndStatePath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // QueryStateAfterEvents implements RoomserverQueryAPI func (h *httpRoomserverInternalAPI) QueryStateAfterEvents( ctx context.Context, request *api.QueryStateAfterEventsRequest, response *api.QueryStateAfterEventsResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryStateAfterEvents") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryStateAfterEventsPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // QueryEventsByID implements RoomserverQueryAPI func (h *httpRoomserverInternalAPI) QueryEventsByID( ctx context.Context, request *api.QueryEventsByIDRequest, response *api.QueryEventsByIDResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryEventsByID") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryEventsByIDPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } func (h *httpRoomserverInternalAPI) QueryPublishedRooms( ctx context.Context, request *api.QueryPublishedRoomsRequest, response *api.QueryPublishedRoomsResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryPublishedRooms") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryPublishedRoomsPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // QueryMembershipForUser implements RoomserverQueryAPI func (h *httpRoomserverInternalAPI) QueryMembershipForUser( ctx context.Context, request *api.QueryMembershipForUserRequest, response *api.QueryMembershipForUserResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryMembershipForUser") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryMembershipForUserPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // QueryMembershipsForRoom implements RoomserverQueryAPI func (h *httpRoomserverInternalAPI) QueryMembershipsForRoom( ctx context.Context, request *api.QueryMembershipsForRoomRequest, response *api.QueryMembershipsForRoomResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryMembershipsForRoom") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryMembershipsForRoomPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // QueryMembershipsForRoom implements RoomserverQueryAPI func (h *httpRoomserverInternalAPI) QueryServerJoinedToRoom( ctx context.Context, request *api.QueryServerJoinedToRoomRequest, response *api.QueryServerJoinedToRoomResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryServerJoinedToRoom") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryServerJoinedToRoomPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // QueryServerAllowedToSeeEvent implements RoomserverQueryAPI func (h *httpRoomserverInternalAPI) QueryServerAllowedToSeeEvent( ctx context.Context, request *api.QueryServerAllowedToSeeEventRequest, response *api.QueryServerAllowedToSeeEventResponse, ) (err error) { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryServerAllowedToSeeEvent") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryServerAllowedToSeeEventPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // QueryMissingEvents implements RoomServerQueryAPI func (h *httpRoomserverInternalAPI) QueryMissingEvents( ctx context.Context, request *api.QueryMissingEventsRequest, response *api.QueryMissingEventsResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryMissingEvents") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryMissingEventsPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // QueryStateAndAuthChain implements RoomserverQueryAPI func (h *httpRoomserverInternalAPI) QueryStateAndAuthChain( ctx context.Context, request *api.QueryStateAndAuthChainRequest, response *api.QueryStateAndAuthChainResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryStateAndAuthChain") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryStateAndAuthChainPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // PerformBackfill implements RoomServerQueryAPI func (h *httpRoomserverInternalAPI) PerformBackfill( ctx context.Context, request *api.PerformBackfillRequest, response *api.PerformBackfillResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "PerformBackfill") defer span.Finish() apiURL := h.roomserverURL + RoomserverPerformBackfillPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // QueryRoomVersionCapabilities implements RoomServerQueryAPI func (h *httpRoomserverInternalAPI) QueryRoomVersionCapabilities( ctx context.Context, request *api.QueryRoomVersionCapabilitiesRequest, response *api.QueryRoomVersionCapabilitiesResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryRoomVersionCapabilities") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryRoomVersionCapabilitiesPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } // QueryRoomVersionForRoom implements RoomServerQueryAPI func (h *httpRoomserverInternalAPI) QueryRoomVersionForRoom( ctx context.Context, request *api.QueryRoomVersionForRoomRequest, response *api.QueryRoomVersionForRoomResponse, ) error { if roomVersion, ok := h.cache.GetRoomVersion(request.RoomID); ok { response.RoomVersion = roomVersion return nil } span, ctx := opentracing.StartSpanFromContext(ctx, "QueryRoomVersionForRoom") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryRoomVersionForRoomPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) if err == nil { h.cache.StoreRoomVersion(request.RoomID, response.RoomVersion) } return err } func (h *httpRoomserverInternalAPI) QueryCurrentState( ctx context.Context, request *api.QueryCurrentStateRequest, response *api.QueryCurrentStateResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryCurrentState") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryCurrentStatePath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } func (h *httpRoomserverInternalAPI) QueryRoomsForUser( ctx context.Context, request *api.QueryRoomsForUserRequest, response *api.QueryRoomsForUserResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryRoomsForUser") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryRoomsForUserPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } func (h *httpRoomserverInternalAPI) QueryBulkStateContent( ctx context.Context, request *api.QueryBulkStateContentRequest, response *api.QueryBulkStateContentResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryBulkStateContent") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryBulkStateContentPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } func (h *httpRoomserverInternalAPI) QuerySharedUsers( ctx context.Context, req *api.QuerySharedUsersRequest, res *api.QuerySharedUsersResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QuerySharedUsers") defer span.Finish() apiURL := h.roomserverURL + RoomserverQuerySharedUsersPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res) } func (h *httpRoomserverInternalAPI) QueryKnownUsers( ctx context.Context, req *api.QueryKnownUsersRequest, res *api.QueryKnownUsersResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryKnownUsers") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryKnownUsersPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res) } func (h *httpRoomserverInternalAPI) QueryAuthChain( ctx context.Context, req *api.QueryAuthChainRequest, res *api.QueryAuthChainResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryAuthChain") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryAuthChainPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res) } func (h *httpRoomserverInternalAPI) QueryServerBannedFromRoom( ctx context.Context, req *api.QueryServerBannedFromRoomRequest, res *api.QueryServerBannedFromRoomResponse, ) error { span, ctx := opentracing.StartSpanFromContext(ctx, "QueryServerBannedFromRoom") defer span.Finish() apiURL := h.roomserverURL + RoomserverQueryServerBannedFromRoomPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res) } func (h *httpRoomserverInternalAPI) PerformForget(ctx context.Context, req *api.PerformForgetRequest, res *api.PerformForgetResponse) error { span, ctx := opentracing.StartSpanFromContext(ctx, "PerformForget") defer span.Finish() apiURL := h.roomserverURL + RoomserverPerformForgetPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res) }