Skip to content

Commit 2471e15

Browse files
committed
Use custom modelled header
1 parent 97e1fc1 commit 2471e15

File tree

8 files changed

+52
-20
lines changed

8 files changed

+52
-20
lines changed

src/main/scala/com/advancedtelematic/treehub/http/ObjectResource.scala

+6-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.advancedtelematic.treehub.http
33
import java.io.File
44

55
import akka.http.scaladsl.model.StatusCodes
6-
import akka.http.scaladsl.server.{Directive0, Directive1, PathMatcher1}
6+
import akka.http.scaladsl.server._
77
import akka.stream.Materializer
88
import com.advancedtelematic.data.DataType.ObjectId
99
import com.advancedtelematic.libats.data.DataType.Namespace
@@ -36,6 +36,10 @@ class ObjectResource(namespace: Directive1[Namespace],
3636
usageHandler ! UpdateBandwidth(namespace, usageBytes, objectId)
3737
}
3838

39+
import OutOfBandStorageHeader._
40+
41+
private val outOfBandStorageEnabled = validate(objectStore.outOfBandStorageEnabled, "Out of band storage not enabled")
42+
3943
val route = namespace { ns =>
4044
path("objects" / PrefixedObjectId) { objectId =>
4145
head {
@@ -61,11 +65,7 @@ class ObjectResource(namespace: Directive1[Namespace],
6165
complete(objectStore.completeClientUpload(ns, objectId).map(_ => StatusCodes.NoContent))
6266
} ~
6367
(post & hintNamespaceStorage(ns)) {
64-
// TODO: abstract header name/header
65-
// TODO: Refactor all that repeated objectstore code
66-
// TODO: Issue Reject if redirect is disabled, this way will bubble down to accept file anyway
67-
// TODO: ^^^ Write test for that
68-
(headerValueByName("x-ats-accept-redirect") & parameter("size".as[Long])) { (_, size) =>
68+
(outOfBandStorageEnabled & headerValueByType[OutOfBandStorageHeader](()) & parameter("size".as[Long])) { (_, size) =>
6969
onSuccess(objectStore.storeOutOfBand(ns, objectId, size)) { case UploadAt(uri) =>
7070
redirect(uri, StatusCodes.Found)
7171
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.advancedtelematic.treehub.http
2+
3+
import akka.http.scaladsl.model.headers._
4+
5+
import scala.util.{Failure, Success, Try}
6+
7+
8+
object OutOfBandStorageHeader extends ModeledCustomHeaderCompanion[OutOfBandStorageHeader] {
9+
override def name: String = "x-ats-accept-redirect"
10+
11+
override def parse(value: String): Try[OutOfBandStorageHeader] =
12+
if(value == "true")
13+
Success(new OutOfBandStorageHeader)
14+
else
15+
Failure(new IllegalArgumentException(s"invalid value for header $name, valid values: true"))
16+
}
17+
18+
class OutOfBandStorageHeader extends ModeledCustomHeader[OutOfBandStorageHeader] {
19+
override def companion: ModeledCustomHeaderCompanion[OutOfBandStorageHeader] = OutOfBandStorageHeader
20+
21+
override def value(): String = "true"
22+
23+
override def renderInRequests(): Boolean = true
24+
25+
override def renderInResponses(): Boolean = true
26+
}

src/main/scala/com/advancedtelematic/treehub/object_store/BlobStore.scala

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ object BlobStore {
1818
trait BlobStore {
1919
def storeStream(namespace: Namespace, id: ObjectId, size: Long, blob: Source[ByteString, _]): Future[Long]
2020

21+
val supportsOutOfBandStorage: Boolean
22+
2123
def storeOutOfBand(namespace: Namespace, id: ObjectId): Future[OutOfBandStoreResult]
2224

2325
def buildResponse(namespace: Namespace, id: ObjectId): Future[HttpResponse]

src/main/scala/com/advancedtelematic/treehub/object_store/LocalFsBlobStore.scala

+2
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,6 @@ class LocalFsBlobStore(root: Path)(implicit ec: ExecutionContext, mat: Materiali
9090
path
9191
}
9292
}
93+
94+
override val supportsOutOfBandStorage: Boolean = false
9395
}

src/main/scala/com/advancedtelematic/treehub/object_store/ObjectStore.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@ import slick.jdbc.MySQLProfile.api._
1515

1616
import scala.concurrent.{ExecutionContext, Future}
1717

18-
// TODO: Use shapeless union type ?
1918
class ObjectStore(blobStore: BlobStore)(implicit ec: ExecutionContext, db: Database) extends ObjectRepositorySupport {
2019

2120
import scala.async.Async._
2221

2322
def completeClientUpload(namespace: Namespace, id: ObjectId): Future[Unit] =
2423
objectRepository.setCompleted(namespace, id).map(_ => ())
2524

25+
def outOfBandStorageEnabled: Boolean = blobStore.supportsOutOfBandStorage
26+
2627
def storeOutOfBand(namespace: Namespace, id: ObjectId, size: Long): Future[OutOfBandStoreResult] = {
2728
val obj = TObject(namespace, id, size, ObjectStatus.CLIENT_UPLOADING)
2829
lazy val createF = objectRepository.create(obj)

src/main/scala/com/advancedtelematic/treehub/object_store/S3BlobStore.scala

+1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ class S3BlobStore(s3Credentials: S3Credentials, allowRedirects: Boolean)
141141
private def objectFilename(namespace: Namespace, objectId: ObjectId): String =
142142
objectId.path(Paths.get(namespaceDir(namespace))).toString
143143

144+
override val supportsOutOfBandStorage: Boolean = true
144145
}
145146

146147
class S3Credentials(accessKey: String, secretKey: String,

src/test/scala/com/advancedtelematic/treehub/http/ObjectResourceIntegrationSpec.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class ObjectResourceIntegrationSpec extends TreeHubSpec with ScalatestRouteTest
3333
val obj = new ClientTObject()
3434

3535
Post(s"/objects/${obj.prefixedObjectId}?size=${obj.blob.length}", obj.blob)
36-
.addHeader(RawHeader("x-ats-accept-redirect", "true")) ~> routes ~> check {
36+
.addHeader(new OutOfBandStorageHeader) ~> routes ~> check {
3737
status shouldBe StatusCodes.Found
3838
response.header[Location].get.uri.toString() should include("amazonaws.com")
3939
}
@@ -47,7 +47,7 @@ class ObjectResourceIntegrationSpec extends TreeHubSpec with ScalatestRouteTest
4747
val obj = new ClientTObject()
4848

4949
val url = Post(s"/objects/${obj.prefixedObjectId}?size=${obj.blob.length}", obj.blob)
50-
.addHeader(RawHeader("x-ats-accept-redirect", "true")) ~> routes ~> check {
50+
.addHeader(new OutOfBandStorageHeader) ~> routes ~> check {
5151
status shouldBe StatusCodes.Found
5252
response.header[Location].get.uri
5353
}
@@ -71,7 +71,7 @@ class ObjectResourceIntegrationSpec extends TreeHubSpec with ScalatestRouteTest
7171
val obj = new ClientTObject()
7272

7373
Post(s"/objects/${obj.prefixedObjectId}?size=${obj.blob.length}", obj.blob)
74-
.addHeader(RawHeader("x-ats-accept-redirect", "true")) ~> routes ~> check {
74+
.addHeader(new OutOfBandStorageHeader) ~> routes ~> check {
7575
status shouldBe StatusCodes.Found
7676
}
7777

src/test/scala/com/advancedtelematic/treehub/http/ObjectResourceSpec.scala

+10-10
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,12 @@
55
package com.advancedtelematic.treehub.http
66

77
import akka.http.scaladsl.model._
8-
import akka.http.scaladsl.model.headers.RawHeader
8+
import akka.http.scaladsl.unmarshalling.PredefinedFromEntityUnmarshallers.byteArrayUnmarshaller
99
import akka.pattern.ask
1010
import com.advancedtelematic.treehub.db.ObjectRepositorySupport
1111
import com.advancedtelematic.util.FakeUsageUpdate.{CurrentBandwith, CurrentStorage}
1212
import com.advancedtelematic.util.ResourceSpec.ClientTObject
1313
import com.advancedtelematic.util.{ResourceSpec, TreeHubSpec}
14-
import akka.http.scaladsl.unmarshalling.PredefinedFromEntityUnmarshallers.byteArrayUnmarshaller
15-
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport.unmarshaller
16-
import com.advancedtelematic.libats.data.ErrorRepresentation
17-
import com.advancedtelematic.libats.data.ErrorRepresentation._
1814

1915
import scala.concurrent.duration._
2016

@@ -59,13 +55,17 @@ class ObjectResourceSpec extends TreeHubSpec with ResourceSpec with ObjectReposi
5955
}
6056
}
6157

62-
test("cannot use redirects when storage method is local storage") {
58+
test("request is still accepted and valid when client supports out of band storage but server does not") {
6359
val obj = new ClientTObject()
6460

65-
Post(apiUri(s"objects/${obj.prefixedObjectId}?size=${obj.blob.length}"))
66-
.addHeader(RawHeader("x-ats-accept-redirect", "true")) ~> routes ~> check {
67-
status shouldBe StatusCodes.BadRequest
68-
responseAs[ErrorRepresentation].code shouldBe ErrorCodes.OutOfBandStorageNotSupported
61+
Post(apiUri(s"objects/${obj.prefixedObjectId}?size=${obj.blob.length}"), obj.blob)
62+
.addHeader(new OutOfBandStorageHeader) ~> routes ~> check {
63+
status shouldBe StatusCodes.NoContent
64+
}
65+
66+
Get(apiUri(s"objects/${obj.prefixedObjectId}")) ~> routes ~> check {
67+
status shouldBe StatusCodes.OK
68+
responseAs[Array[Byte]] shouldBe obj.blob
6969
}
7070
}
7171

0 commit comments

Comments
 (0)