@@ -84,6 +84,8 @@ APPLICATION_INFO::CreateApplication(IHttpContext& pHttpContext)
84
84
return S_OK;
85
85
}
86
86
87
+ std::wstring pExceptionMessage;
88
+
87
89
try
88
90
{
89
91
const WebConfigConfigurationSource configurationSource (m_pServer.GetAdminManager (), pHttpApplication);
@@ -138,29 +140,43 @@ APPLICATION_INFO::CreateApplication(IHttpContext& pHttpContext)
138
140
}
139
141
return S_OK;
140
142
}
141
- catch (const ConfigurationLoadException &ex)
142
- {
143
- EventLog::Error (
144
- ASPNETCORE_CONFIGURATION_LOAD_ERROR,
145
- ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG,
146
- ex.get_message ().c_str ());
147
- }
148
143
catch (...)
149
144
{
150
145
OBSERVE_CAUGHT_EXCEPTION ();
146
+ pExceptionMessage = CaughtExceptionToString ();
151
147
EventLog::Error (
152
148
ASPNETCORE_CONFIGURATION_LOAD_ERROR,
153
149
ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG,
154
- L" " );
150
+ pExceptionMessage. c_str () );
155
151
}
156
152
153
+ ErrorContext errorContext;
154
+ errorContext.statusCode = 500i16;
155
+ errorContext.subStatusCode = 30i16;
156
+ errorContext.generalErrorType = " ASP.NET Core app failed to start - An exception was thrown during startup" ;
157
+ if (GetLastError () == ERROR_ACCESS_DENIED)
158
+ {
159
+ errorContext.errorReason = " Ensure the application pool process model has write permissions to the shadow copy directory" ;
160
+ }
161
+ // TODO: Depend on show detailed errors or nah?
162
+ errorContext.detailedErrorContent = to_multi_byte_string (pExceptionMessage, CP_UTF8);
163
+ auto page = ANCM_ERROR_PAGE;
164
+
165
+
166
+ auto responseContent = FILE_UTILITY::GetHtml (g_hServerModule,
167
+ page,
168
+ errorContext.statusCode ,
169
+ errorContext.subStatusCode ,
170
+ errorContext.generalErrorType ,
171
+ errorContext.errorReason ,
172
+ errorContext.detailedErrorContent );
157
173
m_pApplication = make_application<ServerErrorApplication>(
158
174
pHttpApplication,
159
175
E_FAIL,
160
176
false /* disableStartupPage */ ,
161
- " " /* responseContent */ ,
162
- 500i16 /* statusCode */ ,
163
- 0i16 /* subStatusCode */ ,
177
+ responseContent /* responseContent */ ,
178
+ errorContext. statusCode /* statusCode */ ,
179
+ errorContext. subStatusCode /* subStatusCode */ ,
164
180
" Internal Server Error" );
165
181
166
182
return S_OK;
@@ -193,7 +209,26 @@ APPLICATION_INFO::TryCreateApplication(IHttpContext& pHttpContext, const ShimOpt
193
209
}
194
210
}
195
211
196
- auto shadowCopyPath = HandleShadowCopy (options, pHttpContext);
212
+ std::filesystem::path shadowCopyPath;
213
+
214
+ // Only support shadow copying for IIS.
215
+ if (options.QueryShadowCopyEnabled () && !m_pServer.IsCommandLineLaunch ())
216
+ {
217
+ try
218
+ {
219
+ shadowCopyPath = HandleShadowCopy (options, pHttpContext, error);
220
+ }
221
+ catch (...)
222
+ {
223
+ OBSERVE_CAUGHT_EXCEPTION ();
224
+ throw ;
225
+ }
226
+
227
+ if (shadowCopyPath.empty ())
228
+ {
229
+ return E_FAIL;
230
+ }
231
+ }
197
232
198
233
RETURN_IF_FAILED (m_handlerResolver.GetApplicationFactory (*pHttpContext.GetApplication (), shadowCopyPath, m_pApplicationFactory, options, error));
199
234
LOG_INFO (L" Creating handler application" );
@@ -275,74 +310,107 @@ APPLICATION_INFO::ShutDownApplication(const bool fServerInitiated)
275
310
* we will start a thread that deletes all other folders in that directory.
276
311
*/
277
312
std::filesystem::path
278
- APPLICATION_INFO::HandleShadowCopy (const ShimOptions& options, IHttpContext& pHttpContext)
313
+ APPLICATION_INFO::HandleShadowCopy (const ShimOptions& options, IHttpContext& pHttpContext, ErrorContext& error )
279
314
{
280
- std::filesystem::path shadowCopyPath;
315
+ std::filesystem::path shadowCopyPath = options.QueryShadowCopyDirectory ();
316
+ std::wstring physicalPath = pHttpContext.GetApplication ()->GetApplicationPhysicalPath ();
281
317
282
- // Only support shadow copying for IIS .
283
- if (options. QueryShadowCopyEnabled () && !m_pServer. IsCommandLineLaunch ())
318
+ // Make shadow copy path absolute .
319
+ if (!shadowCopyPath. is_absolute ())
284
320
{
285
- shadowCopyPath = options. QueryShadowCopyDirectory ( );
286
- std::wstring physicalPath = pHttpContext. GetApplication ()-> GetApplicationPhysicalPath ();
321
+ shadowCopyPath = std::filesystem::absolute ( std::filesystem::path (physicalPath) / shadowCopyPath );
322
+ }
287
323
288
- // Make shadow copy path absolute.
289
- if (!shadowCopyPath.is_absolute ())
290
- {
291
- shadowCopyPath = std::filesystem::absolute (std::filesystem::path (physicalPath) / shadowCopyPath);
292
- }
324
+ // The shadow copy directory itself isn't copied to directly.
325
+ // Instead subdirectories with numerically increasing names are created.
326
+ // This is because on shutdown, the app itself will still have all dlls loaded,
327
+ // meaning we can't copy to the same subdirectory. Therefore, on shutdown,
328
+ // we create a directory that is one larger than the previous largest directory number.
329
+ auto directoryName = 0 ;
330
+ std::string directoryNameStr = " 0" ;
331
+ auto shadowCopyBaseDirectory = std::filesystem::directory_entry (shadowCopyPath);
332
+ if (!shadowCopyBaseDirectory.exists ())
333
+ {
334
+ LOG_INFOF (L" Attempting to Create Directory" );
293
335
294
- // The shadow copy directory itself isn't copied to directly.
295
- // Instead subdirectories with numerically increasing names are created.
296
- // This is because on shutdown, the app itself will still have all dlls loaded,
297
- // meaning we can't copy to the same subdirectory. Therefore, on shutdown,
298
- // we create a directory that is one larger than the previous largest directory number.
299
- auto directoryName = 0 ;
300
- std::string directoryNameStr = " 0" ;
301
- auto shadowCopyBaseDirectory = std::filesystem::directory_entry (shadowCopyPath);
302
- if (!shadowCopyBaseDirectory.exists ())
336
+ auto ret = CreateDirectory (shadowCopyBaseDirectory.path ().wstring ().c_str (), nullptr );
337
+ if (!ret)
303
338
{
304
- CreateDirectory (shadowCopyBaseDirectory.path ().wstring ().c_str (), nullptr );
339
+ LOG_ERRORF (L" Failed to create shadow copy base directory %ls. Error: %d" ,
340
+ shadowCopyBaseDirectory.path ().c_str (),
341
+ GetLastError ());
305
342
}
343
+ }
306
344
307
- for (auto & entry : std::filesystem::directory_iterator (shadowCopyPath))
345
+ for (auto & entry : std::filesystem::directory_iterator (shadowCopyPath))
346
+ {
347
+ if (entry.is_directory ())
308
348
{
309
- if (entry. is_directory ())
349
+ try
310
350
{
311
- try
312
- {
313
- auto tempDirName = entry.path ().filename ().string ();
314
- int intFileName = std::stoi (tempDirName);
315
- if (intFileName > directoryName)
316
- {
317
- directoryName = intFileName;
318
- directoryNameStr = tempDirName;
319
- }
320
- }
321
- catch (...)
351
+ auto tempDirName = entry.path ().filename ().string ();
352
+ int intFileName = std::stoi (tempDirName);
353
+ if (intFileName > directoryName)
322
354
{
323
- OBSERVE_CAUGHT_EXCEPTION () ;
324
- // Ignore any folders that can't be converted to an int.
355
+ directoryName = intFileName ;
356
+ directoryNameStr = tempDirName;
325
357
}
326
358
}
359
+ catch (...)
360
+ {
361
+ OBSERVE_CAUGHT_EXCEPTION ();
362
+ // Ignore any folders that can't be converted to an int.
363
+ }
327
364
}
365
+ }
366
+
367
+ int copiedFileCount = 0 ;
368
+
369
+ shadowCopyPath = shadowCopyPath / directoryNameStr;
370
+ LOG_INFOF (L" Copying from %ls to shadow copy directory %ls." , physicalPath.c_str (), shadowCopyPath.c_str ());
328
371
329
- int copiedFileCount = 0 ;
372
+ // Avoid using canonical for shadowCopyBaseDirectory
373
+ // It could expand to a network drive, or an expanded link folder path
374
+ // We already made it an absolute path relative to the physicalPath above
375
+ try {
376
+ // CopyToDirectory throws exception on failure, therefore don't need to check return value
377
+ Environment::CopyToDirectory (physicalPath, shadowCopyPath, options.QueryCleanShadowCopyDirectory (), shadowCopyBaseDirectory.path (), copiedFileCount);
378
+ }
379
+ catch (const std::system_error& ex)
380
+ {
381
+ auto exWideString = to_wide_string (ex.what (), CP_ACP);
382
+
383
+ std::wstring logMessage = format (L" Failed to copy files from %s to shadow copy directory %s. Error: %s" ,
384
+ physicalPath.c_str (),
385
+ shadowCopyPath.c_str (),
386
+ exWideString.c_str ());
330
387
331
- shadowCopyPath = shadowCopyPath / directoryNameStr;
332
- LOG_INFOF (L" Copying to shadow copy directory %ls." , shadowCopyPath.c_str ());
388
+ LOG_ERRORF (L" %ls" , logMessage.c_str ());
389
+ EventLog::Error (ASPNETCORE_CONFIGURATION_LOAD_ERROR,
390
+ ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG,
391
+ logMessage.c_str ());
333
392
334
- // Avoid using canonical for shadowCopyBaseDirectory
335
- // It could expand to a network drive, or an expanded link folder path
336
- // We already made it an absolute path relative to the physicalPath above
337
- HRESULT hr = Environment::CopyToDirectory (physicalPath, shadowCopyPath, options.QueryCleanShadowCopyDirectory (), shadowCopyBaseDirectory.path (), copiedFileCount);
393
+ // TODO: Better substatus code
394
+ error.statusCode = 500i16;
395
+ error.subStatusCode = 30i16;
338
396
339
- LOG_INFOF (L" Finished copying %d files to shadow copy directory %ls." , copiedFileCount, shadowCopyBaseDirectory.path ().c_str ());
397
+ std::string errorMessage = " Failed to copy to shadow copy directory" ;
398
+ auto exceptionCode = ex.code ().value ();
399
+ if (exceptionCode == ERROR_ACCESS_DENIED || exceptionCode == ERROR_PATH_NOT_FOUND)
400
+ {
401
+ errorMessage = " No permissions to shadow copy directory" ;
402
+ }
340
403
341
- if (hr != S_OK)
404
+ error.generalErrorType = format (" ASP.NET Core app failed to start - %s" , errorMessage.c_str ());
405
+ error.errorReason = format (" Ensure the application pool process model has write permissions to the shadow copy directory %ls" ,
406
+ shadowCopyPath.c_str ());
407
+ if (options.QueryShowDetailedErrors ())
342
408
{
343
- return std::wstring ();
409
+ error. detailedErrorContent = ex. what ();
344
410
}
411
+ return std::wstring ();
345
412
}
346
413
414
+ LOG_INFOF (L" Finished copying %d files to shadow copy directory %ls." , copiedFileCount, shadowCopyBaseDirectory.path ().c_str ());
347
415
return shadowCopyPath;
348
416
}
0 commit comments