Add internal request helpers documentation
diff --git a/src/main/jbake/content/documentation/bundles/servlet-helpers.md b/src/main/jbake/content/documentation/bundles/servlet-helpers.md
index e8f538d..23b6492 100644
--- a/src/main/jbake/content/documentation/bundles/servlet-helpers.md
+++ b/src/main/jbake/content/documentation/bundles/servlet-helpers.md
@@ -1,21 +1,103 @@
-title=Sling Servlet Helpers		
+title=Sling Servlet Helpers and Internal Requests
 type=page
 status=published
-tags=servlets
+tags=servlets,requests
 ~~~~~~
 
-The Sling Servlet Helpers bundle provides mock implementations of the
-`SlingHttpServletRequest`, `SlingHttpServletResponse` and related classes.
+The [Sling Servlet Helpers](https://github.com/apache/sling-org-apache-sling-servlet-helpers) 
+bundle provides mock implementations of the `SlingHttpServletRequest`, `SlingHttpServletResponse`
+and related classes, along with fluent `SlingInternalRequest` and `ServletInternalRequest`
+helpers for internal requests.
 
-Those mock implementations are meant to be used in tests and also with services
-like the `SlingRequestProcessor` when making requests to that service outside of
-an HTTP request processing context.
+The mock request/response implementations are meant to be used in tests and
+also with services like the `SlingRequestProcessor` when making requests to
+that service outside of an HTTP request processing context.
+
+They are used under the hood by the `SlingInternalRequest` and 
+`ServletInternalRequest` helpers to provide a simple and foolproof way
+of executing internal Sling requests.
+
+The [GraphQL Core](https://github.com/apache/sling-org-apache-sling-graphql-core/) module,
+for example, uses them for internal requests that retrieve a GraphQL schema dynamically,
+taking into account the current Resource and request selectors.
 
 See the [automated tests](https://github.com/apache/sling-org-apache-sling-servlet-helpers) 
-of the `servlet-helpers` module for more info.
+of the `servlet-helpers` module for more info, besides the general 
+descriptions found below.
 
 
-## Usage
+## InternalRequest helpers
+
+The internal request helpers use either a `SlingRequestProcessor` to execute internal requests using
+the full Sling request processing pipeline, or a `ServletResolver` to resolve and call a Servlet or Script
+directly. The necessary "mocking" of requests are responses happens under the hood which leads to much
+simpler code than using the mock request/response classes directly.
+
+The latter direct-to-servlet (or script) mode is more efficient but less faithful to the way HTTP requests
+are processed, as it bypasses all Servlet Filters, in particular.
+
+Here's an example using the `SlingInternalRequest` helper - see the test code for more. The
+`ServletInternalRequest` API is very similar but takes a `ServletResolver` and an actual `Resource`
+as its starting points.
+
+    OutputStream os = new SlingInternalRequest(resourceResolver, slingRequestProcessor, path)
+      .withResourceType("website/article/news")
+      .withResourceSuperType("website/article")
+      .withSelectors("print", "a4")
+      .withExtension("pdf")
+      .execute()
+      .checkStatus(200)
+      .checkResponseContentType("application/pdf")
+      .getResponse()
+      .getOutputStream()
+
+Not all servlets and scripts are suitable to be called by the `ServletInternalRequest`, depending
+on their "environmental" requirements like `Request` attributes for example.
+
+
+In case of doubt you can start with the `SlingInternalRequest` helper which uses the `SlingRequestProcessor`
+so that servlets or scripts should see no difference compared to HTTP requests. And once that works you can
+try the more efficient `ServletInternalRequest` helper to check if your scripts and servlets support
+that mode.
+
+In both cases, the standard [Sling Servlet/Script resolution mechanism](/documentation/the-sling-engine/servlets.html)
+is used, which can be useful to execute scripts that are resolved based on the current resource type, for non-HTTP
+operations. Inventing HTTP method names for this is fine and allows for reusing this powerful resolution mechanism
+in other contexts.
+
+### Troubleshooting internal requests
+
+To help map log messages to internal requests, as several of those might be used to handle a single
+HTTP request, the `InternalRequest` parent class of the helpers discussed above sets a log4j 
+_Mapped Diagnostic Context_ (MDC) value with the `sling.InternalRequest`key.
+
+The value of that key provides the essential attributes of the current request, so that using a log
+formatting pattern that displays it, like:
+
+    %-5level [%-50logger{50}] %message ## %mdc{sling.InternalRequest} %n
+
+Causes the internal request information to be logged, like in this example (lines folded
+for readability):
+
+    DEBUG [o.a.s.s.internalrequests.SlingInternalRequest     ]
+       Executing request using the SlingRequestProcessor
+       ## GET P=/content/tags/monitor+array S=null EXT=json RT=samples/tag(null)
+    WARN  [org.apache.sling.engine.impl.request.RequestData  ]
+      SlingRequestProgressTracker not found in request attributes
+      ## GET P=/content/tags/monitor+array S=null EXT=json RT=samples/tag(null)
+    DEBUG [o.a.s.s.resolver.internal.SlingServletResolver    ]
+      Using cached servlet /apps/samples/tag/json.gql
+      ## GET P=/content/tags/monitor+array S=null EXT=json RT=samples/tag(null)
+
+In these log messages, `GET P=/content/tags/monitor+array S=null EXT=json RT=samples/tag(null)` points
+to the current internal request, showing its method, path, selectors, extension, resource type and
+resource supertype.
+
+
+## Mock Request/Response classes
+
+These are useful for testing or if you need to do something that the internal request helpers
+do not support.
 
 ### SlingHttpServletRequest
 
@@ -82,3 +164,4 @@
 
     // validate response body as binary data
     assertArrayEquals(TEST_DATA, response.getOutput());
+