summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2024-04-23 21:54:34 +0100
committerGitHub <noreply@github.com>2024-04-23 22:54:34 +0200
commit90a167a1a2bb52017a412897381b114db595afad (patch)
tree2e3354e1ebe295a6d0b308716e426a03bfbfd2ed
parentaff7a64544ee72069049a5429d625b10e4b390a6 (diff)
test: add private npm registry (#23510)
This commit adds a "private npm registry" to the test server. This registry requires to send an appropriate Authorization header. Towards https://github.com/denoland/deno/issues/16105
-rw-r--r--tests/integration/npm_tests.rs28
-rw-r--r--tests/util/server/src/servers/mod.rs149
2 files changed, 135 insertions, 42 deletions
diff --git a/tests/integration/npm_tests.rs b/tests/integration/npm_tests.rs
index 1b7088e7c..3bfd62680 100644
--- a/tests/integration/npm_tests.rs
+++ b/tests/integration/npm_tests.rs
@@ -3,9 +3,11 @@
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
+use deno_fetch::reqwest;
use pretty_assertions::assert_eq;
use test_util as util;
use test_util::itest;
+use url::Url;
use util::assert_contains;
use util::env_vars_for_npm_tests;
use util::http_server;
@@ -3081,3 +3083,29 @@ fn run_cjs_in_node_modules_folder() {
.run()
.assert_matches_text("hi\n");
}
+
+#[tokio::test]
+async fn test_private_npm_registry() {
+ let _server = http_server();
+
+ // For now just check that private server rejects requests without proper
+ // auth header.
+
+ let client = reqwest::Client::new();
+
+ let url =
+ Url::parse("http://127.0.0.1:4252/npm/registry/@denotest/bin/0.5.0")
+ .unwrap();
+
+ let req = reqwest::Request::new(reqwest::Method::GET, url.clone());
+ let resp = client.execute(req).await.unwrap();
+ assert_eq!(resp.status(), reqwest::StatusCode::UNAUTHORIZED);
+
+ let mut req = reqwest::Request::new(reqwest::Method::GET, url.clone());
+ req.headers_mut().insert(
+ reqwest::header::AUTHORIZATION,
+ reqwest::header::HeaderValue::from_static("Bearer private-reg-token"),
+ );
+ let resp = client.execute(req).await.unwrap();
+ assert_eq!(resp.status(), reqwest::StatusCode::OK);
+}
diff --git a/tests/util/server/src/servers/mod.rs b/tests/util/server/src/servers/mod.rs
index b57e9dd25..bc94c668e 100644
--- a/tests/util/server/src/servers/mod.rs
+++ b/tests/util/server/src/servers/mod.rs
@@ -85,6 +85,7 @@ const H2_GRPC_PORT: u16 = 4246;
const H2S_GRPC_PORT: u16 = 4247;
const REGISTRY_SERVER_PORT: u16 = 4250;
const PROVENANCE_MOCK_SERVER_PORT: u16 = 4251;
+const PRIVATE_NPM_REGISTRY_1_PORT: u16 = 4252;
// Use the single-threaded scheduler. The hyper server is used as a point of
// comparison for the (single-threaded!) benchmarks in cli/bench. We're not
@@ -130,6 +131,8 @@ pub async fn run_all_servers() {
let registry_server_fut = registry::registry_server(REGISTRY_SERVER_PORT);
let provenance_mock_server_fut =
registry::provenance_mock_server(PROVENANCE_MOCK_SERVER_PORT);
+ let private_npm_registry_1_server_fut =
+ wrap_private_npm_registry1(PRIVATE_NPM_REGISTRY_1_PORT);
let server_fut = async {
futures::join!(
@@ -158,6 +161,7 @@ pub async fn run_all_servers() {
h2_grpc_server_fut,
registry_server_fut,
provenance_mock_server_fut,
+ private_npm_registry_1_server_fut,
)
}
.boxed_local();
@@ -1087,49 +1091,9 @@ async fn main_server(
}
// serve npm registry files
- if let Some(suffix) = req
- .uri()
- .path()
- .strip_prefix("/npm/registry/@denotest/")
- .or_else(|| req.uri().path().strip_prefix("/npm/registry/@denotest%2f"))
+ if let Some(resp) = try_serve_npm_registry(&req, file_path.clone()).await
{
- // serve all requests to /npm/registry/@deno using the file system
- // at that path
- match handle_custom_npm_registry_path(suffix) {
- Ok(Some(response)) => return Ok(response),
- Ok(None) => {} // ignore, not found
- Err(err) => {
- return Response::builder()
- .status(StatusCode::INTERNAL_SERVER_ERROR)
- .body(string_body(&format!("{err:#}")))
- .map_err(|e| e.into());
- }
- }
- } else if req.uri().path().starts_with("/npm/registry/") {
- // otherwise, serve based on registry.json and tgz files
- let is_tarball = req.uri().path().ends_with(".tgz");
- if !is_tarball {
- file_path.push("registry.json");
- }
- if let Ok(file) = tokio::fs::read(&file_path).await {
- let file_resp = custom_headers(req.uri().path(), file);
- return Ok(file_resp);
- } else if should_download_npm_packages() {
- if let Err(err) =
- download_npm_registry_file(req.uri(), &file_path, is_tarball).await
- {
- return Response::builder()
- .status(StatusCode::INTERNAL_SERVER_ERROR)
- .body(string_body(&format!("{err:#}")))
- .map_err(|e| e.into());
- };
-
- // serve the file
- if let Ok(file) = tokio::fs::read(&file_path).await {
- let file_resp = custom_headers(req.uri().path(), file);
- return Ok(file_resp);
- }
- }
+ return resp;
} else if let Some(suffix) = req.uri().path().strip_prefix("/deno_std/") {
let file_path = std_path().join(suffix);
if let Ok(file) = tokio::fs::read(&file_path).await {
@@ -1154,6 +1118,51 @@ async fn main_server(
};
}
+const PRIVATE_NPM_REGISTRY_AUTH_TOKEN: &str = "private-reg-token";
+
+async fn wrap_private_npm_registry1(port: u16) {
+ let npm_registry_addr = SocketAddr::from(([127, 0, 0, 1], port));
+ run_server(
+ ServerOptions {
+ addr: npm_registry_addr,
+ kind: ServerKind::Auto,
+ error_msg: "HTTP server error",
+ },
+ private_npm_registry1,
+ )
+ .await;
+}
+
+async fn private_npm_registry1(
+ req: Request<hyper::body::Incoming>,
+) -> Result<Response<UnsyncBoxBody<Bytes, Infallible>>, anyhow::Error> {
+ let auth = req
+ .headers()
+ .get("authorization")
+ .and_then(|x| x.to_str().ok())
+ .unwrap_or_default();
+ if auth != format!("Bearer {}", PRIVATE_NPM_REGISTRY_AUTH_TOKEN) {
+ return Ok(
+ Response::builder()
+ .status(StatusCode::UNAUTHORIZED)
+ .body(empty_body())
+ .unwrap(),
+ );
+ }
+
+ let mut file_path = testdata_path().to_path_buf();
+ file_path.push(&req.uri().path()[1..].replace("%2f", "/"));
+
+ if let Some(resp) = try_serve_npm_registry(&req, file_path).await {
+ return resp;
+ }
+
+ Response::builder()
+ .status(StatusCode::NOT_FOUND)
+ .body(empty_body())
+ .map_err(|e| e.into())
+}
+
fn handle_custom_npm_registry_path(
path: &str,
) -> Result<Option<Response<UnsyncBoxBody<Bytes, Infallible>>>, anyhow::Error> {
@@ -1186,6 +1195,62 @@ fn should_download_npm_packages() -> bool {
std::env::var("DENO_TEST_UTIL_UPDATE_NPM") == Ok("1".to_string())
}
+async fn try_serve_npm_registry(
+ req: &Request<hyper::body::Incoming>,
+ mut file_path: PathBuf,
+) -> Option<Result<Response<UnsyncBoxBody<Bytes, Infallible>>, anyhow::Error>> {
+ if let Some(suffix) = req
+ .uri()
+ .path()
+ .strip_prefix("/npm/registry/@denotest/")
+ .or_else(|| req.uri().path().strip_prefix("/npm/registry/@denotest%2f"))
+ {
+ // serve all requests to /npm/registry/@deno using the file system
+ // at that path
+ match handle_custom_npm_registry_path(suffix) {
+ Ok(Some(response)) => return Some(Ok(response)),
+ Ok(None) => {} // ignore, not found
+ Err(err) => {
+ return Some(
+ Response::builder()
+ .status(StatusCode::INTERNAL_SERVER_ERROR)
+ .body(string_body(&format!("{err:#}")))
+ .map_err(|e| e.into()),
+ );
+ }
+ }
+ } else if req.uri().path().starts_with("/npm/registry/") {
+ // otherwise, serve based on registry.json and tgz files
+ let is_tarball = req.uri().path().ends_with(".tgz");
+ if !is_tarball {
+ file_path.push("registry.json");
+ }
+ if let Ok(file) = tokio::fs::read(&file_path).await {
+ let file_resp = custom_headers(req.uri().path(), file);
+ return Some(Ok(file_resp));
+ } else if should_download_npm_packages() {
+ if let Err(err) =
+ download_npm_registry_file(req.uri(), &file_path, is_tarball).await
+ {
+ return Some(
+ Response::builder()
+ .status(StatusCode::INTERNAL_SERVER_ERROR)
+ .body(string_body(&format!("{err:#}")))
+ .map_err(|e| e.into()),
+ );
+ };
+
+ // serve the file
+ if let Ok(file) = tokio::fs::read(&file_path).await {
+ let file_resp = custom_headers(req.uri().path(), file);
+ return Some(Ok(file_resp));
+ }
+ }
+ }
+
+ None
+}
+
async fn download_npm_registry_file(
uri: &hyper::Uri,
file_path: &PathBuf,