18
18
#include " file_utility.h"
19
19
20
20
extern HINSTANCE g_hServerModule;
21
+ extern BOOL g_fInAppOfflineShutdown;
21
22
22
23
HRESULT
23
24
APPLICATION_INFO::CreateHandler (
@@ -49,7 +50,6 @@ APPLICATION_INFO::CreateHandler(
49
50
while (hr != S_OK)
50
51
{
51
52
// At this point application is either null or shutdown and is returning S_FALSE
52
-
53
53
if (m_pApplication != nullptr )
54
54
{
55
55
LOG_INFO (L" Application went offline" );
@@ -80,11 +80,25 @@ APPLICATION_INFO::CreateApplication(IHttpContext& pHttpContext)
80
80
81
81
return S_OK;
82
82
}
83
+
83
84
try
84
85
{
85
86
const WebConfigConfigurationSource configurationSource (m_pServer.GetAdminManager (), pHttpApplication);
86
87
ShimOptions options (configurationSource);
87
88
89
+ if (g_fInAppOfflineShutdown)
90
+ {
91
+ m_pApplication = make_application<ServerErrorApplication>(
92
+ pHttpApplication,
93
+ E_FAIL,
94
+ options.QueryDisableStartupPage () /* disableStartupPage */ ,
95
+ " " /* responseContent */ ,
96
+ 503i16 /* statusCode */ ,
97
+ 0i16 /* subStatusCode */ ,
98
+ " Application Shutting Down" );
99
+ return S_OK;
100
+ }
101
+
88
102
ErrorContext errorContext;
89
103
errorContext.statusCode = 500i16;
90
104
errorContext.subStatusCode = 0i16;
@@ -130,6 +144,7 @@ APPLICATION_INFO::CreateApplication(IHttpContext& pHttpContext)
130
144
}
131
145
catch (...)
132
146
{
147
+ OBSERVE_CAUGHT_EXCEPTION ();
133
148
EventLog::Error (
134
149
ASPNETCORE_CONFIGURATION_LOAD_ERROR,
135
150
ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG,
@@ -175,13 +190,17 @@ APPLICATION_INFO::TryCreateApplication(IHttpContext& pHttpContext, const ShimOpt
175
190
}
176
191
}
177
192
178
- RETURN_IF_FAILED (m_handlerResolver.GetApplicationFactory (*pHttpContext.GetApplication (), m_pApplicationFactory, options, error));
193
+ auto shadowCopyPath = HandleShadowCopy (options, pHttpContext);
194
+
195
+ RETURN_IF_FAILED (m_handlerResolver.GetApplicationFactory (*pHttpContext.GetApplication (), shadowCopyPath, m_pApplicationFactory, options, error));
179
196
LOG_INFO (L" Creating handler application" );
180
197
181
198
IAPPLICATION * newApplication;
199
+ std::wstring shadowCopyWstring = shadowCopyPath.wstring ();
182
200
RETURN_IF_FAILED (m_pApplicationFactory->Execute (
183
201
&m_pServer,
184
202
&pHttpContext,
203
+ shadowCopyWstring,
185
204
&newApplication));
186
205
187
206
m_pApplication.reset (newApplication);
@@ -206,19 +225,91 @@ APPLICATION_INFO::TryCreateHandler(
206
225
return S_OK;
207
226
}
208
227
}
228
+
209
229
return S_FALSE;
210
230
}
211
231
212
232
VOID
213
233
APPLICATION_INFO::ShutDownApplication (const bool fServerInitiated )
214
234
{
235
+ IAPPLICATION* app = nullptr ;
236
+ {
237
+ SRWExclusiveLock lock (m_applicationLock);
238
+ if (!m_pApplication)
239
+ {
240
+ return ;
241
+ }
242
+ app = m_pApplication.get ();
243
+ }
244
+
245
+ LOG_INFOF (L" Stopping application '%ls'" , QueryApplicationInfoKey ().c_str ());
246
+ app->Stop (fServerInitiated );
247
+
215
248
SRWExclusiveLock lock (m_applicationLock);
216
249
217
- if (m_pApplication)
250
+ m_pApplication = nullptr ;
251
+ m_pApplicationFactory = nullptr ;
252
+ }
253
+
254
+ std::filesystem::path
255
+ APPLICATION_INFO::HandleShadowCopy (const ShimOptions& options, IHttpContext& pHttpContext)
256
+ {
257
+ std::filesystem::path shadowCopyPath;
258
+
259
+ // Only support shadow copying for IIS.
260
+ if (options.QueryShadowCopyEnabled () && !m_pServer.IsCommandLineLaunch ())
218
261
{
219
- LOG_INFOF (L" Stopping application '%ls'" , QueryApplicationInfoKey ().c_str ());
220
- m_pApplication->Stop (fServerInitiated );
221
- m_pApplication = nullptr ;
222
- m_pApplicationFactory = nullptr ;
262
+ shadowCopyPath = options.QueryShadowCopyDirectory ();
263
+ std::wstring physicalPath = pHttpContext.GetApplication ()->GetApplicationPhysicalPath ();
264
+
265
+ // Make shadow copy path absolute.
266
+ if (!shadowCopyPath.is_absolute ())
267
+ {
268
+ shadowCopyPath = std::filesystem::absolute (std::filesystem::path (physicalPath) / shadowCopyPath);
269
+ }
270
+
271
+ // The shadow copy directory itself isn't copied to directly.
272
+ // Instead subdirectories with numerically increasing names are created.
273
+ // This is because on shutdown, the app itself will still have all dlls loaded,
274
+ // meaning we can't copy to the same subdirectory. Therefore, on shutdown,
275
+ // we create a directory that is one larger than the previous largest directory number.
276
+ auto directoryName = 0 ;
277
+ std::string directoryNameStr = " 0" ;
278
+ auto shadowCopyBaseDirectory = std::filesystem::directory_entry (shadowCopyPath);
279
+ if (!shadowCopyBaseDirectory.exists ())
280
+ {
281
+ CreateDirectory (shadowCopyBaseDirectory.path ().wstring ().c_str (), NULL );
282
+ }
283
+
284
+ for (auto & entry : std::filesystem::directory_iterator (shadowCopyPath))
285
+ {
286
+ if (entry.is_directory ())
287
+ {
288
+ try
289
+ {
290
+ auto tempDirName = entry.path ().filename ().string ();
291
+ int intFileName = std::stoi (tempDirName);
292
+ if (intFileName > directoryName)
293
+ {
294
+ directoryName = intFileName;
295
+ directoryNameStr = tempDirName;
296
+ }
297
+ }
298
+ catch (...)
299
+ {
300
+ OBSERVE_CAUGHT_EXCEPTION ();
301
+ // Ignore any folders that can't be converted to an int.
302
+ }
303
+ }
304
+ }
305
+
306
+ shadowCopyPath = shadowCopyPath / directoryNameStr;
307
+ HRESULT hr = Environment::CopyToDirectory (physicalPath, shadowCopyPath, options.QueryCleanShadowCopyDirectory (), std::filesystem::canonical (shadowCopyBaseDirectory.path ()));
308
+ if (hr != S_OK)
309
+ {
310
+ return std::wstring ();
311
+ }
223
312
}
313
+
314
+ return shadowCopyPath;
224
315
}
0 commit comments