001/* 002 * Licensed to DuraSpace under one or more contributor license agreements. 003 * See the NOTICE file distributed with this work for additional information 004 * regarding copyright ownership. 005 * 006 * DuraSpace licenses this file to you under the Apache License, 007 * Version 2.0 (the "License"); you may not use this file except in 008 * compliance with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.fcrepo.integration.http.api; 019 020import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE; 021import static java.nio.charset.StandardCharsets.UTF_8; 022import static javax.ws.rs.core.HttpHeaders.CONTENT_DISPOSITION; 023import static javax.ws.rs.core.HttpHeaders.LINK; 024import static javax.ws.rs.core.Response.Status.BAD_REQUEST; 025import static javax.ws.rs.core.Response.Status.CONFLICT; 026import static javax.ws.rs.core.Response.Status.CREATED; 027import static javax.ws.rs.core.Response.Status.NO_CONTENT; 028import static javax.ws.rs.core.Response.Status.OK; 029import static javax.ws.rs.core.Response.Status.TEMPORARY_REDIRECT; 030import static org.fcrepo.kernel.api.RdfLexicon.NON_RDF_SOURCE; 031import static org.junit.Assert.assertEquals; 032import static org.junit.Assert.assertNull; 033import static org.junit.Assert.assertTrue; 034import java.io.File; 035import java.io.FileWriter; 036import java.io.IOException; 037 038import static org.apache.http.HttpStatus.SC_OK; 039import static org.apache.http.HttpHeaders.CONTENT_LENGTH; 040import static org.apache.http.HttpStatus.SC_CREATED; 041 042import org.apache.commons.io.IOUtils; 043import org.apache.commons.lang3.StringUtils; 044import org.apache.http.client.config.RequestConfig; 045import org.apache.http.client.methods.CloseableHttpResponse; 046import org.apache.http.client.methods.HttpDelete; 047import org.apache.http.client.methods.HttpGet; 048import org.apache.http.client.methods.HttpHead; 049import org.apache.http.client.methods.HttpPost; 050import org.apache.http.client.methods.HttpPut; 051import org.apache.http.client.methods.HttpRequestBase; 052import org.apache.http.client.methods.HttpUriRequest; 053import org.apache.http.entity.StringEntity; 054import org.apache.http.impl.client.CloseableHttpClient; 055import org.apache.http.impl.client.HttpClientBuilder; 056import org.fcrepo.kernel.api.FedoraTypes; 057import org.glassfish.jersey.media.multipart.ContentDisposition; 058import org.junit.Before; 059import org.junit.Rule; 060import org.junit.Test; 061import org.junit.rules.TemporaryFolder; 062import org.springframework.test.context.TestExecutionListeners; 063 064/** 065 * @author whikloj 066 * @since 2018-07-10 067 */ 068@TestExecutionListeners( 069 listeners = { TestIsolationExecutionListener.class }, 070 mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS) 071public class ExternalContentHandlerIT extends AbstractResourceIT { 072 073 @Rule 074 public TemporaryFolder tempFolder = new TemporaryFolder(); 075 076 private static final String NON_RDF_SOURCE_LINK_HEADER = "<" + NON_RDF_SOURCE.getURI() + ">;rel=\"type\""; 077 078 private static final String WANT_DIGEST = "Want-Digest"; 079 080 private static final String DIGEST = "Digest"; 081 082 private static final String TEST_BINARY_CONTENT = "01234567890123456789012345678901234567890123456789"; 083 084 private static final String TEST_SHA_DIGEST_HEADER_VALUE = "sha=9578f951955d37f20b601c26591e260c1e5389bf"; 085 086 private static final String TEST_MD5_DIGEST_HEADER_VALUE = "md5=baed005300234f3d1503c50a48ce8e6f"; 087 088 private static final CloseableHttpClient noFollowClient = HttpClientBuilder.create() 089 .disableRedirectHandling().build(); 090 091 @Before 092 public void setup() throws Exception { 093 tempFolder.create(); 094 } 095 096 @Test 097 public void testProxyRemoteContentTypeForHttpUri() throws Exception { 098 final var externalLocation = createHttpResource("audio/ogg", "xyz"); 099 final String finalLocation = getRandomUniqueId(); 100 101 // Make an external content resource proxying the above URI. 102 final HttpPut put = putObjMethod(finalLocation); 103 put.addHeader(LINK, getExternalContentLinkHeader(externalLocation, "proxy", null)); 104 assertEquals(CREATED.getStatusCode(), getStatus(put)); 105 106 // Get the external content proxy resource. 107 try (final CloseableHttpResponse response = execute(getObjMethod(finalLocation))) { 108 assertEquals(SC_OK, getStatus(response)); 109 assertContentType(response, "audio/ogg"); 110 assertContentLocation(response, externalLocation); 111 assertContentLength(response, 3); 112 } 113 } 114 115 @Test 116 public void testProxyClientContentTypeOverridesRemoteForHttpUri() throws Exception { 117 final var externalLocation = createHttpResource("audio/ogg", "vxyz"); 118 final String finalLocation = getRandomUniqueId(); 119 120 // Make an external content resource proxying the above URI. 121 final HttpPut put = putObjMethod(finalLocation); 122 put.addHeader(LINK, getExternalContentLinkHeader(externalLocation, "proxy", "audio/mp3")); 123 assertEquals(CREATED.getStatusCode(), getStatus(put)); 124 125 // Get the external content proxy resource. 126 try (final CloseableHttpResponse response = execute(getObjMethod(finalLocation))) { 127 assertEquals(SC_OK, getStatus(response)); 128 assertContentType(response, "audio/mp3"); 129 assertContentLocation(response, externalLocation); 130 assertContentLength(response, 4); 131 } 132 } 133 134 @Test 135 public void testCopyRemoteContentTypeForHttpUri() throws Exception { 136 final var externalLocation = createHttpResource("audio/ogg", "xyz"); 137 final String finalLocation = getRandomUniqueId(); 138 139 // Make an external content resource proxying the above URI. 140 final HttpPut put = putObjMethod(finalLocation); 141 put.addHeader(LINK, getExternalContentLinkHeader(externalLocation, "copy", null)); 142 assertEquals(CREATED.getStatusCode(), getStatus(put)); 143 144 // Get the external content proxy resource. 145 try (final CloseableHttpResponse response = execute(getObjMethod(finalLocation))) { 146 assertEquals(SC_OK, getStatus(response)); 147 assertContentType(response, "audio/ogg"); 148 assertContentLength(response, 3); 149 } 150 } 151 152 @Test 153 public void testCopyClientContentTypeOverridesRemoteForHttpUri() throws Exception { 154 final var externalLocation = createHttpResource("audio/ogg", "xyz"); 155 final String finalLocation = getRandomUniqueId(); 156 157 // Make an external content resource proxying the above URI. 158 final HttpPut put = putObjMethod(finalLocation); 159 put.addHeader(LINK, getExternalContentLinkHeader(externalLocation, "copy", "audio/mp3")); 160 assertEquals(CREATED.getStatusCode(), getStatus(put)); 161 162 // Get the external content proxy resource. 163 try (final CloseableHttpResponse response = execute(getObjMethod(finalLocation))) { 164 assertEquals(SC_OK, getStatus(response)); 165 assertContentType(response, "audio/mp3"); 166 assertContentLength(response, 3); 167 } 168 } 169 170 @Test 171 public void testProxyWithWantDigestForLocalFile() throws IOException { 172 173 final File externalFile = createExternalLocalFile(TEST_BINARY_CONTENT); 174 175 final String fileUri = externalFile.toURI().toString(); 176 177 final String id = getRandomUniqueId(); 178 final HttpPut put = putObjMethod(id); 179 put.addHeader(LINK, getExternalContentLinkHeader(fileUri, "proxy", "text/plain")); 180 assertEquals(CREATED.getStatusCode(), getStatus(put)); 181 182 final String expectedDigestHeaderValue = TEST_SHA_DIGEST_HEADER_VALUE; 183 184 // HEAD request with Want-Digest 185 final HttpHead headObjMethod = headObjMethod(id); 186 headObjMethod.addHeader(WANT_DIGEST, "sha"); 187 checkExternalDataStreamResponseHeader(headObjMethod, fileUri, expectedDigestHeaderValue); 188 189 // GET request with Want-Digest 190 final HttpGet getObjMethod = getObjMethod(id); 191 getObjMethod.addHeader(WANT_DIGEST, "sha"); 192 checkExternalDataStreamResponseHeader(getObjMethod, fileUri, expectedDigestHeaderValue); 193 } 194 195 @Test 196 public void testCopyWithWantDigestForLocalFile() throws IOException { 197 198 final File externalFile = createExternalLocalFile(TEST_BINARY_CONTENT); 199 200 final String fileUri = externalFile.toURI().toString(); 201 202 final String id = getRandomUniqueId(); 203 final HttpPut put = putObjMethod(id); 204 put.addHeader(LINK, getExternalContentLinkHeader(fileUri, "copy", "text/plain")); 205 assertEquals(CREATED.getStatusCode(), getStatus(put)); 206 207 final String expectedDigestHeaderValue = TEST_SHA_DIGEST_HEADER_VALUE; 208 209 // HEAD request with Want-Digest 210 final HttpHead headObjMethod = headObjMethod(id); 211 headObjMethod.addHeader(WANT_DIGEST, "sha"); 212 checkExternalDataStreamResponseHeader(headObjMethod, null, expectedDigestHeaderValue); 213 214 // GET request with Want-Digest 215 final HttpGet getObjMethod = getObjMethod(id); 216 getObjMethod.addHeader(WANT_DIGEST, "sha"); 217 checkExternalDataStreamResponseHeader(getObjMethod, null, expectedDigestHeaderValue); 218 } 219 220 @Test 221 public void testProxyWithWantDigestForHttpUri() throws Exception { 222 223 final String dsUrl = createHttpResource(TEST_BINARY_CONTENT); 224 225 final String id = getRandomUniqueId(); 226 final HttpPut put = putObjMethod(id); 227 put.addHeader(LINK, getExternalContentLinkHeader(dsUrl, "proxy", "text/plain")); 228 assertEquals(CREATED.getStatusCode(), getStatus(put)); 229 230 final String expectedDigestHeaderValue = TEST_SHA_DIGEST_HEADER_VALUE; 231 232 // HEAD request with Want-Digest 233 final HttpHead headObjMethod = headObjMethod(id); 234 headObjMethod.addHeader(WANT_DIGEST, "sha"); 235 checkExternalDataStreamResponseHeader(headObjMethod, dsUrl, expectedDigestHeaderValue); 236 237 // GET request with Want-Digest 238 final HttpGet getObjMethod = getObjMethod(id); 239 getObjMethod.addHeader(WANT_DIGEST, "sha"); 240 checkExternalDataStreamResponseHeader(getObjMethod, dsUrl, expectedDigestHeaderValue); 241 } 242 243 @Test 244 public void testCopyWithWantDigestForHttpUri() throws Exception { 245 246 final String dsUrl = createHttpResource(TEST_BINARY_CONTENT); 247 248 final String id = getRandomUniqueId(); 249 final HttpPut put = putObjMethod(id); 250 put.addHeader(LINK, getExternalContentLinkHeader(dsUrl, "copy", "text/plain")); 251 assertEquals(CREATED.getStatusCode(), getStatus(put)); 252 253 final String expectedDigestHeaderValue = TEST_SHA_DIGEST_HEADER_VALUE; 254 255 // HEAD request with Want-Digest 256 final HttpHead headObjMethod = headObjMethod(id); 257 headObjMethod.addHeader(WANT_DIGEST, "sha"); 258 checkExternalDataStreamResponseHeader(headObjMethod, null, expectedDigestHeaderValue); 259 260 // GET request with Want-Digest 261 final HttpGet getObjMethod = getObjMethod(id); 262 getObjMethod.addHeader(WANT_DIGEST, "sha"); 263 checkExternalDataStreamResponseHeader(getObjMethod, null, expectedDigestHeaderValue); 264 } 265 266 @Test 267 public void testProxyWithWantDigestMultipleForLocalFile() throws IOException { 268 269 final File externalFile = createExternalLocalFile(TEST_BINARY_CONTENT); 270 271 final String fileUri = externalFile.toURI().toString(); 272 273 final String id = getRandomUniqueId(); 274 final HttpPut put = putObjMethod(id); 275 put.addHeader(LINK, getExternalContentLinkHeader(fileUri, "proxy", "text/plain")); 276 assertEquals(CREATED.getStatusCode(), getStatus(put)); 277 278 // HEAD request with Want-Digest 279 final HttpHead headObjMethod = headObjMethod(id); 280 headObjMethod.addHeader(WANT_DIGEST, "sha, md5;q=0.3"); 281 try (final CloseableHttpResponse response = execute(headObjMethod)) { 282 assertEquals(OK.getStatusCode(), response.getStatusLine().getStatusCode()); 283 assertContentLocation(response, fileUri); 284 assertTrue(response.getHeaders(DIGEST).length > 0); 285 286 final String digesterHeaderValue = response.getHeaders(DIGEST)[0].getValue(); 287 assertTrue("SHA-1 Fixity Checksum doesn't match", 288 digesterHeaderValue.contains(TEST_SHA_DIGEST_HEADER_VALUE)); 289 assertTrue("MD5 fixity checksum doesn't match", 290 digesterHeaderValue.contains(TEST_MD5_DIGEST_HEADER_VALUE)); 291 } 292 293 // GET request with Want-Digest 294 final HttpGet getObjMethod = getObjMethod(id); 295 getObjMethod.addHeader(WANT_DIGEST, "sha, md5;q=0.3"); 296 try (final CloseableHttpResponse response = execute(getObjMethod)) { 297 assertEquals(OK.getStatusCode(), response.getStatusLine().getStatusCode()); 298 assertContentLocation(response, fileUri); 299 assertTrue(response.getHeaders(DIGEST).length > 0); 300 301 final String digesterHeaderValue = response.getHeaders(DIGEST)[0].getValue(); 302 assertTrue("SHA-1 Fixity Checksum doesn't match", 303 digesterHeaderValue.contains(TEST_SHA_DIGEST_HEADER_VALUE)); 304 assertTrue("MD5 fixity checksum doesn't match", 305 digesterHeaderValue.contains(TEST_MD5_DIGEST_HEADER_VALUE)); 306 } 307 } 308 309 private File createExternalLocalFile(final String content) throws IOException { 310 final File externalFile = tempFolder.newFile(); 311 try (final FileWriter fw = new FileWriter(externalFile)) { 312 fw.write(content); 313 } 314 return externalFile; 315 } 316 317 private void checkExternalDataStreamResponseHeader(final HttpUriRequest req, final String contenLocation, 318 final String shaValue) throws IOException { 319 try (final CloseableHttpResponse response = execute(req)) { 320 assertEquals(OK.getStatusCode(), response.getStatusLine().getStatusCode()); 321 assertTrue(response.getHeaders(DIGEST).length > 0); 322 if (StringUtils.isNoneBlank(contenLocation)) { 323 assertEquals(contenLocation, getContentLocation(response)); 324 } 325 final String digesterHeaderValue = response.getHeaders(DIGEST)[0].getValue(); 326 assertTrue("Fixity Checksum doesn't match", 327 digesterHeaderValue.equals(shaValue)); 328 } 329 } 330 331 @Test 332 public void testHeadExternalDatastreamRedirectForHttpUri() throws Exception { 333 334 final String externalLocation = createHttpResource(TEST_BINARY_CONTENT); 335 336 final String id = getRandomUniqueId(); 337 final HttpPut put = putObjMethod(id); 338 put.addHeader(LINK, getExternalContentLinkHeader(externalLocation, "redirect", "image/jpeg")); 339 assertEquals(CREATED.getStatusCode(), getStatus(put)); 340 341 // Configure HEAD request to NOT follow redirects 342 final HttpHead headObjMethod = headObjMethod(id); 343 final RequestConfig.Builder requestConfig = RequestConfig.custom(); 344 requestConfig.setRedirectsEnabled(false); 345 headObjMethod.setConfig(requestConfig.build()); 346 347 try (final CloseableHttpResponse response = execute(headObjMethod)) { 348 assertEquals(TEMPORARY_REDIRECT.getStatusCode(), response.getStatusLine().getStatusCode()); 349 assertLocation(response, externalLocation); 350 assertEquals("bytes", response.getFirstHeader("Accept-Ranges").getValue()); 351 assertContentLength(response, 0); 352 assertContentType(response, "image/jpeg"); 353 final ContentDisposition disposition = 354 new ContentDisposition(response.getFirstHeader(CONTENT_DISPOSITION).getValue()); 355 assertEquals("attachment", disposition.getType()); 356 } 357 } 358 359 @Test 360 public void testGetExternalDatastreamForHttpUri() throws Exception { 361 362 final String externalLocation = createHttpResource(TEST_BINARY_CONTENT); 363 364 final String id = getRandomUniqueId(); 365 final HttpPut put = putObjMethod(id); 366 put.addHeader(LINK, getExternalContentLinkHeader(externalLocation, "redirect", "image/jpeg")); 367 assertEquals(CREATED.getStatusCode(), getStatus(put)); 368 369 // Configure HEAD request to NOT follow redirects 370 final HttpGet getObjMethod = getObjMethod(id); 371 final RequestConfig.Builder requestConfig = RequestConfig.custom(); 372 requestConfig.setRedirectsEnabled(false); 373 getObjMethod.setConfig(requestConfig.build()); 374 375 try (final CloseableHttpResponse response = execute(getObjMethod)) { 376 assertEquals(TEMPORARY_REDIRECT.getStatusCode(), response.getStatusLine().getStatusCode()); 377 assertLocation(response, externalLocation); 378 assertContentType(response, "image/jpeg"); 379 assertEquals("bytes", response.getFirstHeader("Accept-Ranges").getValue()); 380 final ContentDisposition disposition = 381 new ContentDisposition(response.getFirstHeader(CONTENT_DISPOSITION).getValue()); 382 assertEquals("attachment", disposition.getType()); 383 } 384 } 385 386 private void checkRedirectWantDigestResult(final HttpRequestBase request, final String dsUrl, final String sha1, 387 final String md5) throws IOException { 388 try (final CloseableHttpResponse response = execute(request)) { 389 assertEquals(TEMPORARY_REDIRECT.getStatusCode(), response.getStatusLine().getStatusCode()); 390 assertLocation(response, dsUrl); 391 assertTrue(response.getHeaders(DIGEST).length > 0); 392 393 final String digesterHeaderValue = response.getHeaders(DIGEST)[0].getValue(); 394 assertTrue("SHA-1 Fixity Checksum doesn't match", 395 digesterHeaderValue.contains(sha1)); 396 if (md5 != null) { 397 assertTrue("MD5 fixity checksum doesn't match", 398 digesterHeaderValue.contains(md5)); 399 } 400 } 401 } 402 403 @Test 404 public void testRedirectWithWantDigest() throws Exception { 405 406 final String dsUrl = createHttpResource(TEST_BINARY_CONTENT); 407 408 final String id = getRandomUniqueId(); 409 final HttpPut put = putObjMethod(id); 410 put.addHeader(LINK, getExternalContentLinkHeader(dsUrl, "redirect", "image/jpeg")); 411 assertEquals(CREATED.getStatusCode(), getStatus(put)); 412 413 // Configure request to NOT follow redirects 414 final RequestConfig.Builder requestConfig = RequestConfig.custom(); 415 requestConfig.setRedirectsEnabled(false); 416 417 // Verify HEAD request behavior with single Want-Digest 418 final HttpHead headObjMethod = headObjMethod(id); 419 headObjMethod.addHeader(WANT_DIGEST, "sha"); 420 headObjMethod.setConfig(requestConfig.build()); 421 422 checkRedirectWantDigestResult(headObjMethod, dsUrl, 423 TEST_SHA_DIGEST_HEADER_VALUE, null); 424 425 // Verify HEAD request behavior with multiple Want-Digest 426 final HttpHead headObjMethodMulti = headObjMethod(id); 427 headObjMethodMulti.addHeader(WANT_DIGEST, "sha, md5;q=0.3"); 428 headObjMethodMulti.setConfig(requestConfig.build()); 429 430 checkRedirectWantDigestResult(headObjMethodMulti, dsUrl, 431 TEST_SHA_DIGEST_HEADER_VALUE, TEST_MD5_DIGEST_HEADER_VALUE); 432 433 // Verify GET request behavior with Want-Digest 434 final HttpGet getObjMethod = getObjMethod(id); 435 getObjMethod.addHeader(WANT_DIGEST, "sha"); 436 getObjMethod.setConfig(requestConfig.build()); 437 438 checkRedirectWantDigestResult(getObjMethod, dsUrl, 439 TEST_SHA_DIGEST_HEADER_VALUE, null); 440 441 // Verify GET with multiple Want-Digest 442 final HttpGet getObjMethodMulti = getObjMethod(id); 443 getObjMethodMulti.addHeader(WANT_DIGEST, "sha, md5;q=0.3"); 444 getObjMethodMulti.setConfig(requestConfig.build()); 445 446 checkRedirectWantDigestResult(getObjMethodMulti, dsUrl, 447 TEST_SHA_DIGEST_HEADER_VALUE, TEST_MD5_DIGEST_HEADER_VALUE); 448 } 449 450 @Test 451 public void testRedirectForHttpUri() throws Exception { 452 453 final String externalLocation = createHttpResource(TEST_BINARY_CONTENT); 454 455 final String id = getRandomUniqueId(); 456 final HttpPut httpPut = putObjMethod(id); 457 httpPut.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 458 httpPut.addHeader(LINK, getExternalContentLinkHeader(externalLocation, "redirect", null)); 459 460 try (final CloseableHttpResponse response = execute(httpPut)) { 461 assertEquals("Didn't get a CREATED response!", CREATED.getStatusCode(), getStatus(response)); 462 final HttpGet get = new HttpGet(getLocation(response)); 463 try (final CloseableHttpResponse getResponse = noFollowClient.execute(get)) { 464 assertEquals(TEMPORARY_REDIRECT.getStatusCode(), getStatus(getResponse)); 465 assertLocation(getResponse, externalLocation); 466 } 467 } 468 } 469 470 @Test 471 public void testProxyLocalFile() throws Exception { 472 final File localFile = createExternalLocalFile(TEST_BINARY_CONTENT); 473 474 final String id = getRandomUniqueId(); 475 final HttpPut httpPut = putObjMethod(id); 476 httpPut.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 477 final String fileUri = localFile.toURI().toString(); 478 httpPut.addHeader(LINK, getExternalContentLinkHeader(fileUri, "proxy", "text/plain")); 479 480 try (final CloseableHttpResponse response = execute(httpPut)) { 481 assertEquals("Didn't get a CREATED response!", CREATED.getStatusCode(), getStatus(response)); 482 final HttpGet get = new HttpGet(getLocation(response)); 483 try (final CloseableHttpResponse getResponse = execute(get)) { 484 assertEquals(OK.getStatusCode(), getStatus(getResponse)); 485 assertContentLocation(getResponse, fileUri); 486 assertContentLength(getResponse, TEST_BINARY_CONTENT.length()); 487 assertBodyMatches(getResponse, TEST_BINARY_CONTENT); 488 } 489 } 490 } 491 492 @Test 493 public void testCopyLocalFile() throws Exception { 494 final String entityStr = "Hello there, this is the original object speaking."; 495 496 final File localFile = createExternalLocalFile(entityStr); 497 498 final String id = getRandomUniqueId(); 499 final HttpPut httpPut = putObjMethod(id); 500 httpPut.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 501 final String localPath = localFile.toURI().toString(); 502 httpPut.addHeader(LINK, getExternalContentLinkHeader(localPath, "copy", "text/plain")); 503 504 try (final CloseableHttpResponse response = execute(httpPut)) { 505 assertEquals("Didn't get a CREATED response!", CREATED.getStatusCode(), getStatus(response)); 506 507 // fetch the copy of the object 508 final HttpGet get = new HttpGet(getLocation(response)); 509 try (final CloseableHttpResponse getResponse = execute(get)) { 510 assertEquals(OK.getStatusCode(), getStatus(getResponse)); 511 assertContentType(getResponse, "text/plain"); 512 assertBodyMatches(getResponse, entityStr); 513 } 514 } 515 } 516 517 @Test 518 public void testCopyForHttpUri() throws Exception { 519 // create a random binary object 520 final var entityStr = "Hello there, this is the original object speaking."; 521 final String copyLocation = createHttpResource(entityStr); 522 523 // create a copy of it 524 final String id = getRandomUniqueId(); 525 final HttpPut httpPut = putObjMethod(id); 526 httpPut.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 527 httpPut.addHeader(LINK, getExternalContentLinkHeader(copyLocation, "copy", "text/plain")); 528 529 try (final CloseableHttpResponse response = execute(httpPut)) { 530 assertEquals("Didn't get a CREATED response!", CREATED.getStatusCode(), getStatus(response)); 531 532 // fetch the copy of the object 533 final HttpGet get = new HttpGet(getLocation(response)); 534 try (final CloseableHttpResponse getResponse = execute(get)) { 535 assertEquals(OK.getStatusCode(), getStatus(getResponse)); 536 assertContentType(getResponse, "text/plain"); 537 assertBodyMatches(getResponse, entityStr); 538 } 539 } 540 } 541 542 @Test 543 public void testProxyForHttpUri() throws Exception { 544 // Create a resource 545 final String entityStr = "Hello there, this is the original object speaking."; 546 final String origLocation = createHttpResource(entityStr); 547 548 final String id = getRandomUniqueId(); 549 final HttpPut httpPut = putObjMethod(id); 550 httpPut.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 551 httpPut.addHeader(LINK, getExternalContentLinkHeader(origLocation, "proxy", null)); 552 553 try (final CloseableHttpResponse response = execute(httpPut)) { 554 assertEquals("Didn't get a CREATED response!", CREATED.getStatusCode(), getStatus(response)); 555 final HttpGet get = new HttpGet(getLocation(response)); 556 try (final CloseableHttpResponse getResponse = execute(get)) { 557 assertEquals(OK.getStatusCode(), getStatus(getResponse)); 558 assertContentLocation(getResponse, origLocation); 559 assertBodyMatches(getResponse, entityStr); 560 } 561 } 562 } 563 564 @Test 565 public void testPostExternalContentProxyForHttpUri() throws Exception { 566 // Create a resource 567 final String entityStr = "Hello there, this is the original object speaking."; 568 final String origLocation = createHttpResource(entityStr); 569 570 final String id = getRandomUniqueId(); 571 final HttpPost httpPost = postObjMethod(); 572 httpPost.addHeader("Slug", id); 573 httpPost.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 574 httpPost.addHeader(LINK, getExternalContentLinkHeader(origLocation, "proxy", "text/plain")); 575 576 try (final CloseableHttpResponse response = execute(httpPost)) { 577 assertEquals("Didn't get a CREATED response!", CREATED.getStatusCode(), getStatus(response)); 578 final HttpGet get = new HttpGet(getLocation(response)); 579 try (final CloseableHttpResponse getResponse = execute(get)) { 580 assertEquals(OK.getStatusCode(), getStatus(getResponse)); 581 assertContentLocation(getResponse, origLocation); 582 assertContentType(getResponse, "text/plain"); 583 assertBodyMatches(getResponse, entityStr); 584 } 585 } 586 } 587 588 @Test 589 public void testUnsupportedHandlingTypeInExternalMessagePUT() throws IOException { 590 591 final String id = getRandomUniqueId(); 592 final HttpPut httpPut = putObjMethod(id); 593 httpPut.addHeader(LINK, getExternalContentLinkHeader("http://example.com/test", "junk", "image/jpeg")); 594 595 try (final CloseableHttpResponse response = execute(httpPut)) { 596 assertEquals("Didn't get a BAD REQUEST error!", BAD_REQUEST.getStatusCode(), 597 getStatus(response)); 598 assertBodyContains(response, "External content link header url is malformed"); 599 } 600 } 601 602 @Test 603 public void testUnsupportedHandlingTypeInExternalMessagePOST() throws IOException { 604 final HttpPost httpPost = postObjMethod(); 605 httpPost.addHeader(LINK, getExternalContentLinkHeader("http://example.com/junk", "junk", "image/jpeg")); 606 607 try (final CloseableHttpResponse response = execute(httpPost)) { 608 assertEquals("Didn't get a BAD_REQUEST response!", BAD_REQUEST.getStatusCode(), 609 getStatus(response)); 610 assertBodyContains(response, "External content link header url is malformed"); 611 } 612 } 613 614 @Test 615 public void testMissingHandlingTypeInExternalMessage() throws IOException { 616 final String id = getRandomUniqueId(); 617 final HttpPut httpPut = putObjMethod(id); 618 httpPut.addHeader(LINK, getExternalContentLinkHeader("http://example.com/junk", null, "image/jpeg")); 619 620 try (final CloseableHttpResponse response = execute(httpPut)) { 621 assertEquals("Didn't get a BAD_REQUEST response!", BAD_REQUEST.getStatusCode(), 622 getStatus(response)); 623 assertBodyContains(response, "External content link header url is malformed"); 624 } 625 } 626 627 @Test 628 public void testCopyNotFoundHttpContent() throws Exception { 629 final String nonexistentPath = serverAddress + getRandomUniqueId(); 630 631 // create a copy of it 632 final HttpPost httpPost = postObjMethod(); 633 httpPost.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 634 httpPost.addHeader(LINK, getExternalContentLinkHeader(nonexistentPath, "copy", null)); 635 636 try (final CloseableHttpResponse response = execute(httpPost)) { 637 assertEquals("Didn't get a BAD_REQUEST response!", BAD_REQUEST.getStatusCode(), 638 getStatus(response)); 639 assertBodyContains(response, "Unable to access external binary"); 640 } 641 } 642 643 @Test 644 public void testCopyUnreachableHttpContent() throws Exception { 645 final String nonexistentPath = "http://" + getRandomUniqueId() + ".example.com/"; 646 647 // create a copy of it 648 final HttpPost httpPost = postObjMethod(); 649 httpPost.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 650 httpPost.addHeader(LINK, getExternalContentLinkHeader(nonexistentPath, "copy", null)); 651 652 try (final CloseableHttpResponse response = execute(httpPost)) { 653 assertEquals("Didn't get a BAD_REQUEST response!", BAD_REQUEST.getStatusCode(), 654 getStatus(response)); 655 assertBodyContains(response, "Unable to access external binary"); 656 } 657 } 658 659 @Test 660 public void testProxyNotFoundHttpContent() throws Exception { 661 final String nonexistentPath = serverAddress + getRandomUniqueId(); 662 663 // create a copy of it 664 final HttpPost httpPost = postObjMethod(); 665 httpPost.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 666 httpPost.addHeader(LINK, getExternalContentLinkHeader(nonexistentPath, "proxy", null)); 667 668 try (final CloseableHttpResponse response = execute(httpPost)) { 669 assertEquals("Expected failure on creation", BAD_REQUEST.getStatusCode(), 670 getStatus(response)); 671 assertBodyContains(response, "Unable to access external binary"); 672 } 673 } 674 675 @Test 676 public void testProxyUnreachableHttpContent() throws Exception { 677 final String nonexistentPath = "http://" + getRandomUniqueId() + ".example.com/"; 678 679 // create a copy of it 680 final HttpPost httpPost = postObjMethod(); 681 httpPost.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 682 httpPost.addHeader(LINK, getExternalContentLinkHeader(nonexistentPath, "proxy", null)); 683 684 try (final CloseableHttpResponse response = execute(httpPost)) { 685 assertEquals("Expected failure on creation", BAD_REQUEST.getStatusCode(), 686 getStatus(response)); 687 assertBodyContains(response, "Unable to access external binary"); 688 } 689 } 690 691 @Test 692 public void testRedirectUnreachableHttpContent() throws Exception { 693 final String nonexistentPath = "http://" + getRandomUniqueId() + ".example.com/"; 694 695 // create a copy of it 696 final HttpPost httpPost = postObjMethod(); 697 httpPost.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 698 httpPost.addHeader(LINK, getExternalContentLinkHeader(nonexistentPath, "redirect", null)); 699 700 try (final CloseableHttpResponse response = execute(httpPost)) { 701 assertEquals("Expected failure on creation", BAD_REQUEST.getStatusCode(), 702 getStatus(response)); 703 assertBodyContains(response, "Unable to access external binary"); 704 } 705 } 706 707 @Test 708 public void testProxyNotFoundLocalFile() throws Exception { 709 verifyNotFoundLocalFile("proxy"); 710 } 711 712 @Test 713 public void testRedirectNotFoundLocalFile() throws Exception { 714 verifyNotFoundLocalFile("redirect"); 715 } 716 717 @Test 718 public void testCopyNotFoundLocalFile() throws Exception { 719 verifyNotFoundLocalFile("copy"); 720 } 721 722 private void verifyNotFoundLocalFile(final String handling) throws Exception { 723 final File nonexistentFile = tempFolder.newFile(); 724 nonexistentFile.delete(); 725 final String nonexistentUri = nonexistentFile.toURI().toString(); 726 727 // create a copy of it 728 final HttpPost httpPost = postObjMethod(); 729 httpPost.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 730 httpPost.addHeader(LINK, getExternalContentLinkHeader(nonexistentUri, handling, null)); 731 732 try (final CloseableHttpResponse response = execute(httpPost)) { 733 assertEquals("Expected failure on creation", BAD_REQUEST.getStatusCode(), 734 getStatus(response)); 735 assertBodyContains(response, "Path did not match any allowed external content paths"); 736 } 737 } 738 739 @Test 740 public void testCopyWithTransmissionFixityForLocalFile() throws Exception { 741 final File localFile = createExternalLocalFile(TEST_BINARY_CONTENT); 742 743 final String localPath = localFile.toURI().toString(); 744 final HttpPut httpPut = setupExternalContentPut(localPath, "copy", "text/plain"); 745 httpPut.addHeader("Digest", TEST_SHA_DIGEST_HEADER_VALUE); 746 747 try (final CloseableHttpResponse response = execute(httpPut)) { 748 assertEquals("Didn't get a CREATED response!", CREATED.getStatusCode(), getStatus(response)); 749 750 // fetch the copy of the object 751 final HttpGet get = new HttpGet(getLocation(response)); 752 try (final CloseableHttpResponse getResponse = execute(get)) { 753 assertEquals(OK.getStatusCode(), getStatus(getResponse)); 754 assertContentType(getResponse, "text/plain"); 755 assertBodyMatches(getResponse, TEST_BINARY_CONTENT); 756 } 757 } 758 } 759 760 @Test 761 public void testCopyWithInvalidTransmissionFixityForLocalFile() throws Exception { 762 final String content = "Not the expected content"; 763 final File localFile = createExternalLocalFile(content); 764 final String localPath = localFile.toURI().toString(); 765 766 final HttpPut httpPut = setupExternalContentPut(localPath, "copy", "text/plain"); 767 httpPut.addHeader("Digest", TEST_SHA_DIGEST_HEADER_VALUE); 768 769 try (final CloseableHttpResponse response = execute(httpPut)) { 770 assertEquals(CONFLICT.getStatusCode(), getStatus(response)); 771 } 772 } 773 774 @Test 775 public void testCopyWithTransmissionFixityForHttpUri() throws Exception { 776 final String externalLocation = createHttpResource("text/plain", TEST_BINARY_CONTENT); 777 final HttpPut httpPut = setupExternalContentPut(externalLocation, "copy", "text/plain"); 778 httpPut.addHeader("Digest", TEST_SHA_DIGEST_HEADER_VALUE); 779 780 try (final CloseableHttpResponse response = execute(httpPut)) { 781 assertEquals("Didn't get a CREATED response!", CREATED.getStatusCode(), getStatus(response)); 782 783 // fetch the copy of the object 784 final HttpGet get = new HttpGet(getLocation(response)); 785 try (final CloseableHttpResponse getResponse = execute(get)) { 786 assertEquals(OK.getStatusCode(), getStatus(getResponse)); 787 assertContentType(getResponse, "text/plain"); 788 assertBodyMatches(getResponse, TEST_BINARY_CONTENT); 789 } 790 } 791 } 792 793 @Test 794 public void testProxyWithTransmissionFixityForLocalFile() throws Exception { 795 final File localFile = createExternalLocalFile(TEST_BINARY_CONTENT); 796 797 final String externalLocation = localFile.toURI().toString(); 798 final HttpPut httpPut = setupExternalContentPut(externalLocation, "proxy", "text/plain"); 799 httpPut.addHeader("Digest", TEST_SHA_DIGEST_HEADER_VALUE); 800 801 try (final CloseableHttpResponse response = execute(httpPut)) { 802 assertEquals("Didn't get a CREATED response!", CREATED.getStatusCode(), getStatus(response)); 803 assertIsProxyBinary(getLocation(response), externalLocation, TEST_BINARY_CONTENT, "text/plain"); 804 } 805 } 806 807 @Test 808 public void testProxyWithInvalidTransmissionFixityForLocalFile() throws Exception { 809 final File localFile = createExternalLocalFile(TEST_BINARY_CONTENT); 810 811 final String externalLocation = localFile.toURI().toString(); 812 final HttpPut httpPut = setupExternalContentPut(externalLocation, "proxy", "text/plain"); 813 httpPut.addHeader("Digest", "sha=12345678910"); 814 815 try (final CloseableHttpResponse response = execute(httpPut)) { 816 assertEquals(CONFLICT.getStatusCode(), getStatus(response)); 817 } 818 } 819 820 @Test 821 public void testRedirectWithTransmissionFixityForHttpUri() throws Exception { 822 final String externalLocation = createHttpResource("text/plain", TEST_BINARY_CONTENT); 823 final HttpPut httpPut = setupExternalContentPut(externalLocation, "redirect", "text/plain"); 824 httpPut.addHeader("Digest", TEST_SHA_DIGEST_HEADER_VALUE); 825 826 try (final CloseableHttpResponse response = execute(httpPut)) { 827 assertEquals(CREATED.getStatusCode(), getStatus(response)); 828 assertIsRedirectBinary(getLocation(response), externalLocation, TEST_BINARY_CONTENT, "text/plain"); 829 } 830 } 831 832 @Test 833 public void testRedirectWithInvalidTransmissionFixityForHttpUri() throws Exception { 834 final String externalLocation = createHttpResource("text/plain", "bad content"); 835 final HttpPut httpPut = setupExternalContentPut(externalLocation, "redirect", "text/plain"); 836 httpPut.addHeader("Digest", TEST_SHA_DIGEST_HEADER_VALUE); 837 838 try (final CloseableHttpResponse response = execute(httpPut)) { 839 assertEquals(CONFLICT.getStatusCode(), getStatus(response)); 840 } 841 } 842 843 @Test 844 public void testProxyPostWithTransmissionFixityForHttpUri() throws Exception { 845 final String externalLocation = createHttpResource("text/plain", TEST_BINARY_CONTENT); 846 final HttpPost httpPost = postObjMethod(); 847 httpPost.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 848 httpPost.addHeader(LINK, getExternalContentLinkHeader(externalLocation, "proxy", "text/plain")); 849 httpPost.addHeader("Digest", TEST_SHA_DIGEST_HEADER_VALUE); 850 851 try (final CloseableHttpResponse response = execute(httpPost)) { 852 assertEquals(CREATED.getStatusCode(), getStatus(response)); 853 assertIsProxyBinary(getLocation(response), externalLocation, TEST_BINARY_CONTENT, "text/plain"); 854 } 855 } 856 857 @Test 858 public void testProxyPostWithInvalidTransmissionFixityForHttpUri() throws Exception { 859 final String externalLocation = createHttpResource("text/plain", "bad content"); 860 final HttpPost httpPost = postObjMethod(); 861 httpPost.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 862 httpPost.addHeader(LINK, getExternalContentLinkHeader(externalLocation, "proxy", "text/plain")); 863 httpPost.addHeader("Digest", TEST_SHA_DIGEST_HEADER_VALUE); 864 865 try (final CloseableHttpResponse response = execute(httpPost)) { 866 assertEquals(CONFLICT.getStatusCode(), getStatus(response)); 867 } 868 } 869 870 @Test 871 public void testRedirectPostWithTransmissionFixityForHttpUri() throws Exception { 872 final String externalLocation = createHttpResource("text/plain", TEST_BINARY_CONTENT); 873 final HttpPost httpPost = postObjMethod(); 874 httpPost.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 875 httpPost.addHeader(LINK, getExternalContentLinkHeader(externalLocation, "redirect", "text/plain")); 876 httpPost.addHeader("Digest", TEST_SHA_DIGEST_HEADER_VALUE); 877 878 try (final CloseableHttpResponse response = execute(httpPost)) { 879 assertEquals(CREATED.getStatusCode(), getStatus(response)); 880 assertIsRedirectBinary(getLocation(response), externalLocation, TEST_BINARY_CONTENT, "text/plain"); 881 } 882 } 883 884 @Test 885 public void testRedirectPostWithInvalidTransmissionFixityForHttpUri() throws Exception { 886 final String externalLocation = createHttpResource("text/plain", "bad content"); 887 final HttpPost httpPost = postObjMethod(); 888 httpPost.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 889 httpPost.addHeader(LINK, getExternalContentLinkHeader(externalLocation, "redirect", "text/plain")); 890 httpPost.addHeader("Digest", TEST_SHA_DIGEST_HEADER_VALUE); 891 892 try (final CloseableHttpResponse response = execute(httpPost)) { 893 assertEquals(CONFLICT.getStatusCode(), getStatus(response)); 894 } 895 } 896 897 @Test 898 public void testProxyPutWithTransmissionFixityForHttpUri() throws Exception { 899 final String externalLocation = createHttpResource("text/plain", TEST_BINARY_CONTENT); 900 901 final HttpPut httpPut = setupExternalContentPut(externalLocation, "proxy", "text/plain"); 902 httpPut.addHeader("Digest", TEST_SHA_DIGEST_HEADER_VALUE); 903 904 try (final CloseableHttpResponse response = execute(httpPut)) { 905 assertEquals(CREATED.getStatusCode(), getStatus(response)); 906 assertIsProxyBinary(getLocation(response), externalLocation, TEST_BINARY_CONTENT, "text/plain"); 907 } 908 } 909 910 @Test 911 public void testUpdateProxyHttpUri() throws Exception { 912 final String content2 = "<doc>some more content</doc>"; 913 final String externalLocation1 = createHttpResource("text/plain", TEST_BINARY_CONTENT); 914 final String externalLocation2 = createHttpResource("text/xml", content2); 915 916 final String rescLoc = createExternalContentResource(externalLocation1, "proxy", null); 917 assertIsProxyBinary(rescLoc, externalLocation1, TEST_BINARY_CONTENT, "text/plain"); 918 919 updateExternalContentResource(rescLoc, externalLocation2, "proxy", null); 920 assertIsProxyBinary(rescLoc, externalLocation2, content2, "text/xml"); 921 } 922 923 @Test 924 public void testUpdateProxyLocalFile() throws Exception { 925 final String content2 = "<doc>some more content</doc>"; 926 final File localFile1 = createExternalLocalFile(TEST_BINARY_CONTENT); 927 final File localFile2 = createExternalLocalFile(content2); 928 final String externalLocation1 = localFile1.toURI().toString(); 929 final String externalLocation2 = localFile2.toURI().toString(); 930 931 final String rescLoc = createExternalContentResource(externalLocation1, "proxy", null); 932 assertIsProxyBinary(rescLoc, externalLocation1, TEST_BINARY_CONTENT, "application/octet-stream"); 933 934 updateExternalContentResource(rescLoc, externalLocation2, "proxy", "text/xml"); 935 assertIsProxyBinary(rescLoc, externalLocation2, content2, "text/xml"); 936 } 937 938 @Test 939 public void testUpdateRedirectHttpUri() throws Exception { 940 final String content2 = "<doc>some more content</doc>"; 941 final String externalLocation1 = createHttpResource("text/plain", TEST_BINARY_CONTENT); 942 final String externalLocation2 = createHttpResource(content2); 943 944 final String rescLoc = createExternalContentResource(externalLocation1, "redirect", null); 945 assertIsRedirectBinary(rescLoc, externalLocation1, TEST_BINARY_CONTENT, "text/plain"); 946 947 updateExternalContentResource(rescLoc, externalLocation2, "redirect", "text/xml"); 948 assertIsRedirectBinary(rescLoc, externalLocation2, content2, "text/xml"); 949 } 950 951 @Test 952 public void testUpdateProxyToRedirectForHttpUri() throws Exception { 953 // Create a resource 954 final String externalLocation = createHttpResource(TEST_BINARY_CONTENT); 955 956 final String rescLoc = createExternalContentResource(externalLocation, "proxy", null); 957 assertIsProxyBinary(rescLoc, externalLocation, TEST_BINARY_CONTENT, null); 958 959 updateExternalContentResource(rescLoc, externalLocation, "redirect", null); 960 assertIsRedirectBinary(rescLoc, externalLocation, TEST_BINARY_CONTENT, null); 961 } 962 963 @Test 964 public void testUpdateRedirectToProxyForHttpUri() throws Exception { 965 final String externalLocation = createHttpResource(TEST_BINARY_CONTENT); 966 967 final String rescLoc = createExternalContentResource(externalLocation, "redirect", null); 968 assertIsRedirectBinary(rescLoc, externalLocation, TEST_BINARY_CONTENT, null); 969 970 updateExternalContentResource(rescLoc, externalLocation, "proxy", null); 971 assertIsProxyBinary(rescLoc, externalLocation, TEST_BINARY_CONTENT, null); 972 } 973 974 @Test 975 public void testUpdateProxyToRedirectForLocalFile() throws Exception { 976 final String content2 = "<doc>some more content</doc>"; 977 final File localFile1 = createExternalLocalFile(TEST_BINARY_CONTENT); 978 final File localFile2 = createExternalLocalFile(content2); 979 final String externalLocation1 = localFile1.toURI().toString(); 980 final String externalLocation2 = localFile2.toURI().toString(); 981 982 final String rescLoc = createExternalContentResource(externalLocation1, "proxy", "text/plain"); 983 assertIsProxyBinary(rescLoc, externalLocation1, TEST_BINARY_CONTENT, "text/plain"); 984 985 updateExternalContentResource(rescLoc, externalLocation2, "redirect", "text/xml"); 986 // Not checking on the content, since following a redirect on a file is unlikely to work 987 assertIsRedirectBinary(rescLoc, externalLocation2, null, "text/xml"); 988 } 989 990 @Test 991 public void testUpdateHttpUriToLocalFile() throws Exception { 992 final String content2 = "some more content"; 993 final String externalLocation1 = createHttpResource(TEST_BINARY_CONTENT); 994 final File localFile2 = createExternalLocalFile(content2); 995 final String externalLocation2 = localFile2.toURI().toString(); 996 997 final String rescLoc = createExternalContentResource(externalLocation1, "proxy", null); 998 assertIsProxyBinary(rescLoc, externalLocation1, TEST_BINARY_CONTENT, "text/plain"); 999 1000 updateExternalContentResource(rescLoc, externalLocation2, "proxy", null); 1001 assertIsProxyBinary(rescLoc, externalLocation2, content2, "application/octet-stream"); 1002 } 1003 1004 @Test 1005 public void testUpdateInternalToLocalFile() throws Exception { 1006 final String id = getRandomUniqueId(); 1007 final String rescLoc; 1008 try (final CloseableHttpResponse response = execute(putDSMethod(id, "x", TEST_BINARY_CONTENT))) { 1009 assertEquals(CREATED.getStatusCode(), getStatus(response)); 1010 rescLoc = getLocation(response); 1011 } 1012 1013 final String content2 = "<doc>some more content</doc>"; 1014 final File localFile = createExternalLocalFile(content2); 1015 final String externalLocation = localFile.toURI().toString(); 1016 1017 updateExternalContentResource(rescLoc, externalLocation, "proxy", "text/xml"); 1018 assertIsProxyBinary(rescLoc, externalLocation, content2, "text/xml"); 1019 } 1020 1021 @Test 1022 public void testUpdateLocalFileToInternal() throws Exception { 1023 final File localFile = createExternalLocalFile(TEST_BINARY_CONTENT); 1024 final String externalLocation = localFile.toURI().toString(); 1025 1026 final String rescLoc = createExternalContentResource(externalLocation, "proxy", "text/plain"); 1027 assertIsProxyBinary(rescLoc, externalLocation, TEST_BINARY_CONTENT, "text/plain"); 1028 1029 final String content2 = "<doc>some more content</doc>"; 1030 final HttpPut put = new HttpPut(rescLoc); 1031 put.setEntity(new StringEntity(content2)); 1032 put.setHeader(CONTENT_TYPE, "text/xml"); 1033 assertEquals(NO_CONTENT.getStatusCode(), getStatus(put)); 1034 1035 final HttpGet get = new HttpGet(rescLoc); 1036 try (final CloseableHttpResponse resp = execute(get)) { 1037 assertEquals(OK.getStatusCode(), getStatus(resp)); 1038 assertNull(resp.getFirstHeader("Content-Location")); 1039 assertContentLength(resp, content2.length()); 1040 assertBodyMatches(resp, content2); 1041 assertContentType(resp, "text/xml"); 1042 } 1043 } 1044 1045 @Test 1046 public void testUpdateInternalToHttpUri() throws Exception { 1047 final String id = getRandomUniqueId(); 1048 final String rescLoc; 1049 try (final CloseableHttpResponse response = execute(putDSMethod(id, "x", TEST_BINARY_CONTENT))) { 1050 assertEquals(CREATED.getStatusCode(), getStatus(response)); 1051 rescLoc = getLocation(response); 1052 } 1053 1054 final String content2 = "<doc>some more content</doc>"; 1055 final String externalLocation = createHttpResource(content2); 1056 1057 updateExternalContentResource(rescLoc, externalLocation, "redirect", "text/xml"); 1058 assertIsRedirectBinary(rescLoc, externalLocation, content2, "text/xml"); 1059 } 1060 1061 @Test 1062 public void testUpdateHttpUriToInternal() throws Exception { 1063 final String externalLocation = createHttpResource(TEST_BINARY_CONTENT); 1064 1065 final String rescLoc = createExternalContentResource(externalLocation, "proxy", null); 1066 assertIsProxyBinary(rescLoc, externalLocation, TEST_BINARY_CONTENT, "text/plain"); 1067 1068 final String content2 = "<doc>some more content</doc>"; 1069 final HttpPut put = new HttpPut(rescLoc); 1070 put.setEntity(new StringEntity(content2)); 1071 put.setHeader(CONTENT_TYPE, "text/xml"); 1072 assertEquals(NO_CONTENT.getStatusCode(), getStatus(put)); 1073 1074 final HttpGet get = new HttpGet(rescLoc); 1075 try (final CloseableHttpResponse resp = execute(get)) { 1076 assertEquals(OK.getStatusCode(), getStatus(resp)); 1077 assertNull(resp.getFirstHeader("Content-Location")); 1078 assertContentLength(resp, content2.length()); 1079 assertBodyMatches(resp, content2); 1080 assertContentType(resp, "text/xml"); 1081 } 1082 } 1083 1084 @Test 1085 public void testLocalFileNotDeleted() throws Exception { 1086 final File localFile = createExternalLocalFile(TEST_BINARY_CONTENT); 1087 final String externalLocation = localFile.toURI().toString(); 1088 1089 final String rescLoc = createExternalContentResource(externalLocation, "proxy", "text/plain"); 1090 final String id = StringUtils.substringAfterLast(rescLoc, "/"); 1091 assertIsProxyBinary(rescLoc, externalLocation, TEST_BINARY_CONTENT, "text/plain"); 1092 1093 final HttpDelete delete = new HttpDelete(rescLoc); 1094 assertEquals(NO_CONTENT.getStatusCode(), getStatus(delete)); 1095 assertDeleted(id); 1096 assertTrue("External binary must exist after resource deletion", localFile.exists()); 1097 1098 final HttpDelete deleteTomb = new HttpDelete(rescLoc + "/" + FedoraTypes.FCR_TOMBSTONE); 1099 assertEquals(NO_CONTENT.getStatusCode(), getStatus(deleteTomb)); 1100 assertTrue("External binary must exist after deleting tombstone", localFile.exists()); 1101 } 1102 1103 private HttpPut setupExternalContentPut(final String externalLocation, final String handling, 1104 final String contentType) { 1105 final String id = getRandomUniqueId(); 1106 final HttpPut httpPut = putObjMethod(id); 1107 httpPut.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 1108 httpPut.addHeader(LINK, getExternalContentLinkHeader(externalLocation, handling, contentType)); 1109 return httpPut; 1110 } 1111 1112 private String createExternalContentResource(final String externalLocation, final String handling, 1113 final String contentType) throws IOException { 1114 final HttpPut httpPut = setupExternalContentPut(externalLocation, handling, contentType); 1115 1116 try (final CloseableHttpResponse response = execute(httpPut)) { 1117 assertEquals(CREATED.getStatusCode(), getStatus(response)); 1118 1119 return getLocation(response); 1120 } 1121 } 1122 1123 private void updateExternalContentResource(final String rescLoc, final String externalLocation, 1124 final String handling, final String contentType) throws IOException { 1125 final HttpPut httpPut = new HttpPut(rescLoc); 1126 httpPut.addHeader(LINK, getExternalContentLinkHeader(externalLocation, handling, contentType)); 1127 try (final CloseableHttpResponse response = execute(httpPut)) { 1128 assertEquals(NO_CONTENT.getStatusCode(), getStatus(response)); 1129 } 1130 } 1131 1132 private void assertIsProxyBinary(final String rescLocation, final String expectedLocation, 1133 final String expectedContent, final String expectedType) throws IOException { 1134 final HttpGet get = new HttpGet(rescLocation); 1135 try (final CloseableHttpResponse resp = execute(get)) { 1136 assertEquals(OK.getStatusCode(), getStatus(resp)); 1137 assertContentLocation(resp, expectedLocation); 1138 assertContentLength(resp, expectedContent.length()); 1139 assertBodyMatches(resp, expectedContent); 1140 if (expectedType != null) { 1141 assertContentType(resp, expectedType); 1142 } 1143 } 1144 } 1145 1146 private void assertIsRedirectBinary(final String rescLocation, final String expectedLocation, 1147 final String expectedContent, final String expectedType) throws IOException { 1148 final HttpGet get = new HttpGet(rescLocation); 1149 try (final CloseableHttpResponse resp = noFollowClient.execute(get)) { 1150 assertEquals(TEMPORARY_REDIRECT.getStatusCode(), getStatus(resp)); 1151 assertLocation(resp, expectedLocation); 1152 if (expectedType != null) { 1153 assertContentType(resp, expectedType); 1154 } 1155 } 1156 1157 if (expectedContent != null) { 1158 // Follow redirect to the content 1159 try (final CloseableHttpResponse resp = execute(get)) { 1160 assertBodyMatches(resp, expectedContent); 1161 assertContentLength(resp, expectedContent.length()); 1162 } 1163 } 1164 } 1165 1166 private String createHttpResource(final String content) throws Exception { 1167 return createHttpResource("text/plain", content); 1168 } 1169 1170 private String createHttpResource(final String contentType, final String content) throws Exception { 1171 final HttpPost method = postObjMethod(); 1172 method.addHeader(CONTENT_TYPE, contentType); 1173 method.addHeader(LINK, NON_RDF_SOURCE_LINK_HEADER); 1174 method.setEntity(new StringEntity(content)); 1175 1176 // Make an external remote URI. 1177 try (final CloseableHttpResponse response = execute(method)) { 1178 assertEquals(SC_CREATED, getStatus(response)); 1179 return getLocation(response); 1180 } 1181 } 1182 1183 private void assertBodyContains(final CloseableHttpResponse response, final String expected) throws IOException { 1184 final String body = IOUtils.toString(response.getEntity().getContent(), UTF_8); 1185 assertTrue("Expected response to contain '" + expected + "' but was '" + body + "'", 1186 body.contains(expected)); 1187 } 1188 1189 private void assertBodyMatches(final CloseableHttpResponse response, final String expected) throws IOException { 1190 final String body = IOUtils.toString(response.getEntity().getContent(), UTF_8); 1191 assertEquals("Response body did not match the expected value", expected, body); 1192 } 1193 1194 private void assertContentLength(final CloseableHttpResponse response, final long expectedLength) { 1195 assertEquals("Content-length header did not match", expectedLength, Long.parseLong(response 1196 .getFirstHeader(CONTENT_LENGTH).getValue())); 1197 } 1198 1199 private void assertContentType(final CloseableHttpResponse response, final String expected) { 1200 assertEquals("Content-type header did not match", expected, response.getFirstHeader(CONTENT_TYPE).getValue()); 1201 } 1202 1203 private void assertContentLocation(final CloseableHttpResponse response, final String expectedLoc) { 1204 assertEquals("Content location header did not match", expectedLoc, getContentLocation(response)); 1205 } 1206 1207 private void assertLocation(final CloseableHttpResponse response, final String expectedLoc) { 1208 assertEquals("Location header did not match", expectedLoc, getLocation(response)); 1209 } 1210}