Skip to content

Commit

Permalink
Support serving static assets (#29)
Browse files Browse the repository at this point in the history
Signed-off-by: Juan Cruz Viotti <[email protected]>
  • Loading branch information
jviotti authored Nov 13, 2024
1 parent 94a77e8 commit d875f75
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 2 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ option(REGISTRY_DEVELOPMENT "Build the Registry in development mode" OFF)
option(REGISTRY_SERVER "Build the Registry server" ON)
option(REGISTRY_INDEX "Build the Registry index tool" ON)
option(REGISTRY_ENTERPRISE "Build the Registry Enterprise edition (requires a license)" OFF)
set(REGISTRY_PREFIX "/usr" CACHE STRING "Expected installation prefix")

find_package(JSONToolkit REQUIRED)
find_package(Blaze REQUIRED)
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ configure:
-DREGISTRY_INDEX:BOOL=$(INDEX) \
-DREGISTRY_SERVER:BOOL=$(SERVER) \
-DREGISTRY_ENTERPRISE:BOOL=$(ENTERPRISE) \
-DREGISTRY_PREFIX:STRING=$(PREFIX) \
-DBUILD_SHARED_LIBS:BOOL=OFF

.PHONY: compile
Expand Down
14 changes: 13 additions & 1 deletion src/enterprise/enterprise_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "enterprise_explorer.h"

#include <filesystem> // std::filesystem
#include <sstream> // std::ostringstream

namespace sourcemeta::registry::enterprise {

Expand All @@ -18,11 +19,22 @@ auto on_index(const sourcemeta::hydra::http::ServerLogger &,
auto on_request(const sourcemeta::hydra::http::ServerLogger &logger,
const sourcemeta::hydra::http::ServerRequest &request,
sourcemeta::hydra::http::ServerResponse &response) -> void {
const auto extension{std::filesystem::path{request.path()}.extension()};
const auto &request_path{request.path()};
const auto extension{std::filesystem::path{request_path}.extension()};
if (extension == ".json") {
return ::on_request(logger, request, response);
}

// TODO: Prevent relative paths that can let a client
// serve a file outside of the static asset directory
std::ostringstream asset_path_stream;
asset_path_stream << SOURCEMETA_REGISTRY_ENTERPRISE_STATIC << request_path;
const std::string asset_path{asset_path_stream.str()};
if (std::filesystem::exists(asset_path)) {
sourcemeta::hydra::http::serve_file(asset_path, request, response);
return;
}

explore_not_found(response);
}

Expand Down
5 changes: 4 additions & 1 deletion src/enterprise/server.cmake
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
target_compile_definitions(schema_registry_server PRIVATE SOURCEMETA_REGISTRY_ENTERPRISE)

cmake_path(GET CMAKE_CURRENT_LIST_FILE PARENT_PATH ENTERPRISE_SOURCE_DIR)
target_sources(schema_registry_server PRIVATE
"${ENTERPRISE_SOURCE_DIR}/enterprise_server.h"
"${ENTERPRISE_SOURCE_DIR}/enterprise_explorer.h"
"${CMAKE_CURRENT_BINARY_DIR}/style.min.css")
target_include_directories(schema_registry_server PRIVATE "${ENTERPRISE_SOURCE_DIR}")

# Static assets
target_compile_definitions(schema_registry_server
PRIVATE SOURCEMETA_REGISTRY_ENTERPRISE_STATIC="${REGISTRY_PREFIX}/share/sourcemeta/registry")
include(BootstrapFiles)
find_program(SASSC_BIN NAMES sassc REQUIRED)
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/style.min.css"
Expand All @@ -16,7 +20,6 @@ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/style.min.css"
"${ENTERPRISE_SOURCE_DIR}/style.scss"
"${PROJECT_SOURCE_DIR}/vendor/bootstrap-icons/font/bootstrap-icons.scss"
${BOOTSTRAP_SCSS_FILES})

include(GNUInstallDirs)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/style.min.css"
Expand Down
2 changes: 2 additions & 0 deletions src/server/resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ auto resolver(const sourcemeta::jsontoolkit::URI &server_base_url,
}

assert(uri.path().has_value());
// TODO: Prevent a malicious client from requesting a JSON file outside
// the schema directory by using relative paths
const auto schema_path{path_join(schema_base_directory, uri.path().value())};
if (!std::filesystem::exists(schema_path)) {
return std::nullopt;
Expand Down
122 changes: 122 additions & 0 deletions test/e2e/ee/css.hurl
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# HEAD
HEAD {{base}}/style.min.css
HTTP 200
Content-Type: text/css
[Asserts]
bytes count == 0

# Without GZIP
GET {{base}}/style.min.css
HTTP 200
Content-Type: text/css
[Asserts]
bytes count > 0

# With GZIP
GET {{base}}/style.min.css
Accept-Encoding: gzip
HTTP 200
Content-Type: text/css
Content-Encoding: gzip
[Asserts]
bytes count > 0

# Idempotent ETag
GET {{base}}/style.min.css
HTTP 200
[Asserts]
header "ETag" exists
[Captures]
css_etag: header "ETag"
GET {{base}}/style.min.css
HTTP 200
[Asserts]
bytes count > 0
header "ETag" == {{css_etag}}

# If-None-Match with match
GET {{base}}/style.min.css
If-None-Match: {{css_etag}}
HTTP 304
[Asserts]
header "Content-Type" not exists
bytes count == 0

# If-None-Match with weak match
GET {{base}}/style.min.css
If-None-Match: W/{{css_etag}}
HTTP 304
[Asserts]
header "Content-Type" not exists
bytes count == 0

# If-None-Match without match
GET {{base}}/style.min.css
If-None-Match: "12345"
HTTP 200
Content-Type: text/css
[Asserts]
bytes count > 0

# Last-Modified
GET {{base}}/style.min.css
HTTP 200
[Asserts]
header "Last-Modified" matches /^(Sun|Mon|Tue|Wed|Thu|Fri|Sat), [0-3][0-9] (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} [0-2][0-9]:[0-5][0-9]:[0-5][0-9] GMT$/

# Idempotent Last-Modified
GET {{base}}/style.min.css
HTTP 200
[Asserts]
header "Last-Modified" exists
[Captures]
css_last_modified: header "Last-Modified"
GET {{base}}/style.min.css
HTTP 200
[Asserts]
header "Last-Modified" == {{css_last_modified}}

# Invalid If-Modified-Since
GET {{base}}/style.min.css
If-Modified-Since: FOO
Content-Type: text/css
HTTP 200
[Asserts]
bytes count > 0

# If-Modified-Since exact
GET {{base}}/style.min.css
If-Modified-Since: {{css_last_modified}}
HTTP 304
[Asserts]
header "Content-Type" not exists
bytes count == 0

# If-Modified-Since false
GET {{base}}/style.min.css
If-Modified-Since: Thu, 01 Jan 2100 00:00:00 GMT
HTTP 304
[Asserts]
header "Content-Type" not exists
bytes count == 0

# If-Modified-Since true
GET {{base}}/style.min.css
If-Modified-Since: Thu, 01 Jan 1970 00:00:00 GMT
HTTP 200
Content-Type: text/css
[Asserts]
bytes count > 0

# Proper HEAD
GET {{base}}/style.min.css
HTTP 200
[Asserts]
header "Content-Length" exists
[Captures]
css_content_length: header "Content-Length"
HEAD {{base}}/style.min.css
HTTP 200
[Asserts]
header "Content-Length" exists
header "Content-Length" == {{css_content_length}}

0 comments on commit d875f75

Please sign in to comment.