Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KTOR-7470 receiveMultipart throw UnsupportedMediaTypeException #4339

Merged
merged 16 commits into from
Nov 21, 2024

Conversation

stokado
Copy link
Contributor

@stokado stokado commented Sep 25, 2024

Subsystem
Server, related modules

Motivation
Return 415 Unsupported Media-Type if client passed the wrong Content-Type header or didn't pass any value at all. KTOR-7470

Solution
Given no Content-Type header, throw UnsupportedMediaTypeException with corresponding message.
Given bad Content-Type header, rethrow UnsupportedMediaTypeException.

@stokado stokado changed the title issue/ktor 7470 receiveMultipart throw UnsupportedMediaTypeException KTOR-7470 receiveMultipart throw UnsupportedMediaTypeException Sep 25, 2024
@e5l e5l requested a review from marychatte October 7, 2024 05:40
@e5l
Copy link
Member

e5l commented Oct 7, 2024

@marychatte, could you check?

Copy link
Member

@marychatte marychatte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR, please check the comments

contentLength,
call.formFieldLimit
)
} catch (_: IOException) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need try-catch here? It's a constructor method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not have an access to UnsupportedMediaTypeException in CIO module

I had to catch an exception on the server and rethrow it here, it is the latest server code before CIO module

This should answer this question

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Can we add a check that the exception message contains "Content-Type " because another IOException also thrown

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added this check, but maybe there could be a way to add UnsupportedMediaTypeException to CIO module or create separate Exception for the Unsupported Media errors in CIO?

Not sure if it is a common practice to define catch logic based on exception's message

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, adding UnsupportedMediaTypeException to CIO module is a breaking change so can we please create a new Exception in CIO module UnsupportedMediaTypeExceptionCIO and catch it in DefaultTransformJvm?

private val contentType: ContentType?
) : ContentTransformationException(
contentType?.let { "Content type $it is not supported" }
?: "Content-Type header is required for multipart processing"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Content-Type header may be required not only for multipart requests, we can remove this part

@@ -33,16 +35,21 @@ internal actual suspend fun PipelineContext<Any, PipelineCall>.defaultPlatformTr
@OptIn(InternalAPI::class)
internal actual fun PipelineContext<*, PipelineCall>.multiPartData(rc: ByteReadChannel): MultiPartData {
val contentType = call.request.header(HttpHeaders.ContentType)
?: throw IllegalStateException("Content-Type header is required for multipart processing")
?: throw UnsupportedMediaTypeException(null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is also one more place, where exception is thrown - CIO:
1)

val contentType = headers["Content-Type"] ?: throw IOException("Failed to parse multipart: no Content-Type header")

2)
throw IOException("Failed to parse multipart: Content-Type should be multipart/* but it is $contentType")

Can we please fix it too?

@stokado stokado requested a review from marychatte October 10, 2024 13:11
@marychatte
Copy link
Member

Сan we please create a new Exception in CIO module UnsupportedMediaTypeExceptionCIO and catch it in DefaultTransformJvm?

@stokado
Copy link
Contributor Author

stokado commented Nov 12, 2024

Сan we please create a new Exception in CIO module UnsupportedMediaTypeExceptionCIO and catch it in DefaultTransformJvm?

Of course, I will update the PR this week. I was not able to do it earlier :)

Copy link
Member

@marychatte marychatte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work, thank you!
I just fixed codestyle and other minor issues; I will merge the PR after checks

@@ -697,7 +697,7 @@ final class io.ktor.server.plugins/PayloadTooLargeException : io.ktor.server.plu
}

final class io.ktor.server.plugins/UnsupportedMediaTypeException : io.ktor.server.plugins/ContentTransformationException, kotlinx.coroutines/CopyableThrowable<io.ktor.server.plugins/UnsupportedMediaTypeException> { // io.ktor.server.plugins/UnsupportedMediaTypeException|null[0]
constructor <init>(io.ktor.http/ContentType) // io.ktor.server.plugins/UnsupportedMediaTypeException.<init>|<init>(io.ktor.http.ContentType){}[0]
constructor <init>(io.ktor.http/ContentType?) // io.ktor.server.plugins/UnsupportedMediaTypeException.<init>|<init>(io.ktor.http.ContentType?){}[0]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, this change is not binary compatible. Could you add a constructor with an old signature?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added constructor with an old signature
How can I run an apiDump task now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could not run apiDump task on my Windows PC because ios subtasks are failing

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed it with @osipxd and it's binary compatible, I reverted the last commit and will merge the PR

@marychatte marychatte changed the base branch from main to 3.1.0-eap November 20, 2024 13:36
@marychatte marychatte merged commit 86a7bd9 into ktorio:3.1.0-eap Nov 21, 2024
10 of 13 checks passed
@stokado stokado deleted the issue/KTOR-7470 branch December 2, 2024 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants