Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ Report lands at `_build\windows-x86-64-coverage\coverage-report\index.html`.
- **`src/`** — the main application (`CMakeLists.txt` defines target `ModernCppApp`, project `ModernCppApp`). Sources are glob-collected (`*.cpp`/`*.h` in the directory), so **new files under `src/` are picked up automatically at the next CMake configure** — no need to edit `src/CMakeLists.txt` when adding a file there.
- `src/controller/`, `src/model/`, `src/view/` are currently empty placeholder directories (each holds only a `.gitignore`), suggesting an intended MVC split that hasn't been built out yet.
- `src/utils/` is a separate static library target, `ModernCppUtils` (project `ModernCppUtils`), also glob-built and linked into both the app and the test binary. New utility files go here and are picked up the same way.
- `src/module/` is the IIS native module itself: target `IISNativeModule`, a `SHARED` library (DLL) that exports `RegisterModule` via `iis_native_module.def`. `iis::HttpModule` (`http_module.h/.cpp`) overrides every overridable `CHttpModule` method with skeleton bodies returning `RQ_NOTIFICATION_CONTINUE`; `iis::HttpModuleFactory` creates instances; `register_module.cpp` currently subscribes to no notifications (`SetRequestNotifications(factory, 0, 0)`) — add `RQ_*` flags there as methods gain real implementations.
- **`test/`** — GTest-based tests, target/project `ModernCppTest`. Globs both `test/*.cpp` and `test/utils/*.cpp`, and links `ModernCppUtils`. `test/main.cpp` is a standard GTest `main()` running `RUN_ALL_TESTS()`. Mirror `src/utils/` layout under `test/utils/` for new utility tests (see `test/utils/smoke_test.cpp` as the existing example — one GTest `TEST` per behavior, wrapped in the same namespace as the code under test).
- Test includes reference library headers as `<utils/smoke.h>` because `test/CMakeLists.txt` adds `test/../src` (i.e. `src/`) to the include path — so app/test code both include utils headers via the `utils/` prefix, not relative paths.
- Because both `src/` and `src/utils/` (and `test/`) use `file(GLOB ...)`, CMake must be **re-run** (re-configure, not just rebuild) after adding or removing source files for them to be picked up — GLOB results are cached at configure time.
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 4.2)

project(ModernCppApp C CXX)

add_subdirectory(module)
add_subdirectory(utils)

file(GLOB SRC_FILES
Expand Down
15 changes: 15 additions & 0 deletions src/module/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 4.2)

project(IISNativeModule C CXX)

file(GLOB MODULE_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/*.h"
)

# The .def file exports RegisterModule, the entry point IIS looks up
# with GetProcAddress when loading the module.
add_library(${PROJECT_NAME} SHARED
${MODULE_FILES}
"${CMAKE_CURRENT_SOURCE_DIR}/iis_native_module.def"
)
188 changes: 188 additions & 0 deletions src/module/http_module.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#include "http_module.h"

namespace iis {

auto HttpModule::OnBeginRequest(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPostBeginRequest(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnAuthenticateRequest(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IAuthenticationProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPostAuthenticateRequest(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnAuthorizeRequest(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPostAuthorizeRequest(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnResolveRequestCache(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPostResolveRequestCache(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnMapRequestHandler(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IMapHandlerProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPostMapRequestHandler(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnAcquireRequestState(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPostAcquireRequestState(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPreExecuteRequestHandler(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPostPreExecuteRequestHandler(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnExecuteRequestHandler(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPostExecuteRequestHandler(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnReleaseRequestState(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPostReleaseRequestState(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnUpdateRequestCache(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPostUpdateRequestCache(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnLogRequest(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPostLogRequest(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnEndRequest(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnPostEndRequest(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IHttpEventProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnSendResponse(
_In_ IHttpContext * /*pHttpContext*/,
_In_ ISendResponseProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnMapPath(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IMapPathProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnReadEntity(
_In_ IHttpContext * /*pHttpContext*/,
_In_ IReadEntityProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnCustomRequestNotification(
_In_ IHttpContext * /*pHttpContext*/,
_In_ ICustomNotificationProvider * /*pProvider*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::OnAsyncCompletion(
_In_ IHttpContext * /*pHttpContext*/,
_In_ DWORD /*dwNotification*/,
_In_ BOOL /*fPostNotification*/,
_In_ IHttpEventProvider * /*pProvider*/,
_In_ IHttpCompletionInfo * /*pCompletionInfo*/) -> REQUEST_NOTIFICATION_STATUS {
return RQ_NOTIFICATION_CONTINUE;
}

auto HttpModule::Dispose() -> VOID {
// Matches the base-class behavior: IIS releases module instances
// through Dispose(), so an empty body here would leak them.
delete this;
}

}
153 changes: 153 additions & 0 deletions src/module/http_module.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#ifndef HTTP_MODULE_H_
#define HTTP_MODULE_H_

#define _WINSOCKAPI_
#include <windows.h>
#include <sal.h>
#include <httpserv.h>

namespace iis {
// Request-level HTTP module skeleton: overrides every overridable
// method of CHttpModule, with empty bodies to be filled in later.
class HttpModule : public CHttpModule {
public:
// RQ_BEGIN_REQUEST
auto OnBeginRequest(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

auto OnPostBeginRequest(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_AUTHENTICATE_REQUEST
auto OnAuthenticateRequest(
_In_ IHttpContext * pHttpContext,
_In_ IAuthenticationProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

auto OnPostAuthenticateRequest(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_AUTHORIZE_REQUEST
auto OnAuthorizeRequest(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

auto OnPostAuthorizeRequest(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_RESOLVE_REQUEST_CACHE
auto OnResolveRequestCache(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

auto OnPostResolveRequestCache(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_MAP_REQUEST_HANDLER
auto OnMapRequestHandler(
_In_ IHttpContext * pHttpContext,
_In_ IMapHandlerProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

auto OnPostMapRequestHandler(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_ACQUIRE_REQUEST_STATE
auto OnAcquireRequestState(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

auto OnPostAcquireRequestState(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_PRE_EXECUTE_REQUEST_HANDLER
auto OnPreExecuteRequestHandler(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

auto OnPostPreExecuteRequestHandler(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_EXECUTE_REQUEST_HANDLER
auto OnExecuteRequestHandler(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

auto OnPostExecuteRequestHandler(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_RELEASE_REQUEST_STATE
auto OnReleaseRequestState(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

auto OnPostReleaseRequestState(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_UPDATE_REQUEST_CACHE
auto OnUpdateRequestCache(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

auto OnPostUpdateRequestCache(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_LOG_REQUEST
auto OnLogRequest(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

auto OnPostLogRequest(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_END_REQUEST
auto OnEndRequest(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

auto OnPostEndRequest(
_In_ IHttpContext * pHttpContext,
_In_ IHttpEventProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_SEND_RESPONSE
auto OnSendResponse(
_In_ IHttpContext * pHttpContext,
_In_ ISendResponseProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_MAP_PATH
auto OnMapPath(
_In_ IHttpContext * pHttpContext,
_In_ IMapPathProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_READ_ENTITY
auto OnReadEntity(
_In_ IHttpContext * pHttpContext,
_In_ IReadEntityProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// RQ_CUSTOM_NOTIFICATION
auto OnCustomRequestNotification(
_In_ IHttpContext * pHttpContext,
_In_ ICustomNotificationProvider * pProvider) -> REQUEST_NOTIFICATION_STATUS override;

// Completion
auto OnAsyncCompletion(
_In_ IHttpContext * pHttpContext,
_In_ DWORD dwNotification,
_In_ BOOL fPostNotification,
_In_ IHttpEventProvider * pProvider,
_In_ IHttpCompletionInfo * pCompletionInfo) -> REQUEST_NOTIFICATION_STATUS override;

auto Dispose() -> VOID override;
};
}
#endif // HTTP_MODULE_H_
24 changes: 24 additions & 0 deletions src/module/http_module_factory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "http_module_factory.h"

#include <new>

#include "http_module.h"

namespace iis {

auto HttpModuleFactory::GetHttpModule(
_Outptr_ CHttpModule ** ppModule,
_In_ IModuleAllocator * /*pAllocator*/) -> HRESULT {
auto * pModule = new (std::nothrow) HttpModule();
if (pModule == nullptr) {
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
*ppModule = pModule;
return S_OK;
}

auto HttpModuleFactory::Terminate() -> VOID {
delete this;
}

}
Loading
Loading