Tuesday, July 25, 2006

Ken Jennings Suspended

After making some unkind remarks about the game show Jeopardy and its host Alex Trebek, Ken Jennings’ web site has been suspended.

Ken_jennings_com_s

Local TV station KSL posted an Associated Press story that indicated Ken Jennings (who allegedly won $2.5 million on Jeopard in 2004) was taking some cheap shots at Jeopardy. At the bottom of the story was a link to http://www.ken-jennings.com; however, attempting to link to Ken Jennings’ web site (hosted on box 79 at www.bluehost.com) resulted in the “This Account Has Exceeded Its CPU Quota” message.

And while Ken Jennings insinuated that Alex Trebek was either a robot or a cyborg, developed by engineers after the “real” Alex Trebek allegedly died in a fiery car crash, his web site might be consuming too many resources, possibly because of inefficiently running scripts (according to the message provided by Jennings’ web hosting company). Not too big a deal — unless of course, you a) are a software engineer, b) your site attracts a lot of web traffic and c) your name is Ken Jennings .

Is it possible that the “real” Ken Jennings never really appeared on Jeopardy but instead sent his robot counterpart to Jeopardy?

 

SQL Server :: Profiler :: Open Traces

Lately, I’ve been doing a lot of troubleshooting on some newly implemented reports in our web application. The problem (slow overall performance) was caused by some SQL queries, and in order to figure out what was taking up a lot of CPU power and execution time, I ran Profiler over a remote desktop connection.

Unfortunately, our Internet connection here in the office is not the most stable connection in the world. And since I have to connect by way of a Virtual Private Network (VPN), I run the risk of getting twice (remote desktop connection + VPN) as soon as we experience even the slightest connection hiccup. Of course, this happens to me on a regular basis.

So, a few days ago, I got disconnected again, leaving my Profiler session running (basically as an orphaned session). To make a long story short, when I finally regained consciousness, er, access to the database server, the actual Profiler window had disappeared, but I was still getting new trace files (since I had been saving the trace output to file).

Task Manager was at a loss, too, as there was no sign of profiler.exe anywhere. And the excellent free Process Explorer form SysInternals did not uncover any easily identifiable Profiler processes either. There had to be someone else who experienced something like this before, right? Yes.

Enter Steve Herbert who offered the following solution (ideally executed by way of Query Analyzer):

select * from :: fn_trace_getinfo(default)

If there are any running traces, this query will display a table with trace-related information. If all of the above fits your situation, take special note of the Trace ID(s), and then run the following command to first close and then stop each running trace:

-- STOP ALL RUNNING TRACES
sp_trace_setstatus 1, 0
sp_trace_setstatus 3, 0


-- CLOSE ALL RUNNING TRACES
sp_trace_setstatus 1, 2
sp_trace_setstatus 3, 2

In my example, the integer immediately following sp_trace_setstatus is the Trace ID. I should also add that SQL Server 2005 apparently always has running trace available, unless you disable it (see the comments on Steve Herbert’s post for more links and information).

Tags: SQL Server 2000, Profiler, profiler.exe, task manager, sp_trace_setstatus, fn_trace_getinfo, trace

 

 

Friday, July 21, 2006

RTF and DOC Files in IE

Some time during the last few weeks, Microsoft must have released a Security Patch or Windows Update that tightened down security between Internet Explorer (IE) and MS Office documents.

We’ve been getting a lot of calls lately from clients who are using our web application to upload HR related forms, notes and other documents in PDF, RTF and DOC format. Those documents are then linked to the clients’ customized web GUI and can be retrieved easily by clicking on the corresponding links.

However, it seems that quite a few people — including some of our internal staff — were no longer able to open RTF and DOC files in IE. Bummer in the summer. Of course, since IE displays an error message when that occurs, I was tasked with getting this fixed, because “it was working a week ago, and now it’s not working anymore, and we just don’t think that all of our users have been screwing up their systems at the same time. So it must be something on the server.”

Great. To make a long story short, I went off-site to log in as a client and witnessed first-hand that the RTF and DOC links were no longer working. (My problem is, I have to be able to see the problem myself and re-create an error scenario . . . just hearing someone else describe it to me doesn’t do the trick. Just the facts, m’am!)

However, as oon as I added the HTTPS web site to the Trusted Sites in IE, everything worked just fine again. On top of all of that, the links were working as expected in Firefox and Opera, so I’m 99.99 percent positive that Microsoft tightened security somewhere during the past few weeks.

Monday, July 17, 2006

Determining the Data Type in Classic ASP

When we implemented BrowserHawk into our web application, we were presented with an astonishing array of information, ranging from the end-user’s available color depth to Java options and just about everything in between.

By and large, that information is easy to digest, evaluate and re-use throughout the web application. However, when I recently added another browser detection variable throughout the web application (does the user have Flash enabled in the browser, and if so, which version?), I ran into some issues that could have easily been prevented had I remembered the VBScript VarType() function.

Instead, I presumed I could grab the version number, convert it to an integer (just to make sure) and run with it. Well, it turns out that not everyone in this hemisphere has the Flash plug-in…and some people happen to have astonishingly old versions of that plug-in installed. But who am I to criticize those people?

So, I think I’ve perfected the interpretation of all possible Flash version variables that BrowserHawk could throw at me, like so:

If NOT IsNull(bhObj.Plugin_FlashVerEx) OR NOT IsEmpty(bhObj.Plugin_FlashVerEx) Then
 If VarType(bhObj.Plugin_FlashVerEx) = 8 Then
  Session("Flash") = CInt(Left(bhObj.Plugin_FlashVerEx, 1))
 Else
  Session("Flash") = Left(bhObj.Plugin_FlashVerEx, 1)
 End If
Else
 Session("Flash") = 0
End If

If NOT IsEmpty(Session("Flash")) AND NOT ISNull(Session("Flash")) Then
 If VarType(Session("Flash")) <> 2 Then
  Session("Flash") = CInt(Session("Flash"))
 End If
Else
 Session("Flash") = 0
End If

FYI: bhObj.Plugin_FlashVerEx returns the specific version of the Flash plug-in that’s available to the current web browser. If the end-user has more than one web browser installed, chances are that they are using various versions of the Flash plug-in.

Basically, this code snippet examines the variable that’s returned by BrowserHawk. If it’s empty or NULL, then we’ll set it to 0. If the VarType() function determines that the variable data type is 8 (string), then we’ll convert it to an integer. The LEFT() function makes sure we only get one character returned — and I guess, I’ll have to re-address this issue when Flash Player 10 comes out. For the time being, however, this will do. (The bhObj.Plugin_FlashVerEx variable returns funky information, similar to 7,0,7,7.)

If I wanted to be extra careful, I could add an IsNumeric() check before converting the one character to an integer; however, at the present, BrowserHawk does always return an integer (albeit in string format) as the first character for this particular variable.

For what it’s worth.

 

Use ALTER DATABASE to reduce FILEGROWTH . . .

Since I did some (unpaid) upgrading and security patching on our production servers this last Saturday, I really thought Monday was going to be a breeze. Nonetheless, this morning right before 9:00 am, we received a ton of “timeout expired” errors from our web application.

When I remotely logged into the SQL Server 2000 database server, I noticed an intersting entry in the Event Viewer:

File_growth

I found that mildly disturbing, since I had never seen that kind of issue before during the last three years. Of course, I immediately Google-d this issue to death and came to the conclusion that the Microsoft documentation was as helpful as always. NOT! The documentation does mention FILEGROWTH but does not provide clear information on how to implement it (other than when it comes to creating a database or adding files to an existing database).

Luckily, some others have noticed similar SQL Server FILEGROWTH issues and published their findings as well. So, I’m following suit, knowing very well that this article is merely provided to remind myself about this issue the next time it comes up — rather than some kind of ingenious original discussion of FILEGROWTH.

On to the good stuff
First of all, I wanted to know what the current FILEGROWTH settings were either for the data file or the log file. Here’s how I did that:

EXEC sp_helpdb NAME_OF_YOUR_DATABASE
GO

That displayed some very basic but useful information about the database in question — and included the current FILEGROWTH settings. With that information I was able to adjust the FILEGROWTH accordingly. Since I have plenty of available disk space on the server partition that holds the LOG file, I decided to “up” the FILEGROWTH from 1024KB to 5%, like so:

ALTER DATABASE your_database
MODIFY FILE (NAME = your_database_Log, FILEGROWTH = 5%)
GO

After that, I ran the sp_heldb command again to see if things had changed, and everything looked all right. However, some SQL Server 2005 users have reported that this setting might not stick after a reboot and actually turn into a ridiculously high value (such as 2160%). So next time I get to reboot the production database server (probably on Saturday), I’ll have to follow up on this and see what happens.

For now, everything seems to be working well again.

 

 

Event Viewer Message: Autogrow of file 'database_log' in database 'database' cancelled or timed out after 15 ms. Use ALTER DATABASE to set a smaller FILEGROWTH or to set a new size.

Related Links: Brian Kelley Blog

Tags: SQL SERVER 2000, FILEGROWTH, MSSQLSERVER, error, log file, ALTER DATABASE, autogrow, cancelled, timed out, Monday

Wednesday, July 12, 2006

Web Application Security

Last week, I had the opportunity to visit with the CEO of a successful web applications development company. He told me that — in his system — users are authorized on every page throughout the entire web application.

Although I didn’t think the situation was appropriate to nail him down on the details, it made me think about security in my own web applications. Most of my web applications code is written in Classic ASP that I inherited from previous developers. And most of that code contains numerous SQL Server database calls.

Some of you may know what I’m talking about:

1) Issue a SQL statement that retrieves some basic information from the database.
2) If there is a valid record, use the ID from the previously retrieved row and get some more information.
3) If that worked out all right, do something else (an UPDATE or an INSERT, for example).

And sometimes, this goes on an on for many lines of code. I still remember the “old developer” telling me that all of this performs lightning fast on his development system. Yeah, right, one user. Big deal. So, by the time I implemented Stored Procedures (to reduce bandwidth problems and query timeouts, among other things), the “old developer” started feeling a bit uneasy and eventually stopped working for us.

At any rate, here I am still trying to mildly refactor a web application, using Stored Procedures (SP) to spiff up things. Oh, you’re wondering where I’m going with this? The point is that SQL Server SPs are an excellent way to implement system security, too.

For the last little while, I have been rewriting some of the web application code, and while I was ripping out old and redundant ASP-based SQL, and replaced it with SPs, I started validating some basic things in every SP.

For example, in our human resources related web application, the logged in user can add and edit personnel information. And although there’s never been a great risk as far as “hackers” getting into the system to change somebody’s employment history and so forth, I started making sure that this won’t happen.

So, at the top of every SP, I now query the database to find out if the user who is logged in and the employee whose information is getting edited belong to the same company. If they don’t, the SP returns a custom error code. Next, I check the IDs of anything that needs to get updated. Sometimes, that means going to more than one table to “make the connection” and retrieve the needed information. If that ID matches up with the expected data, let’s go ahead and log everything “BEFORE” to the change table, then make the actual update. If there’s a mis-match, however, we’ll raise a custom error and exit the SP.

And so forth and so on. It’s about as mundane as it sounds, and sometimes it really gets to me to be coding this kind of security into every SP (even though I have my own macro tool and other keystroke-saving techniques). However, when a client calls and claims that he can’t do a certain thing because our “stupid” system won’t let him, it’s nice to be able to look up some information in the change table and in our web application log table, and then tell the client that he’s not supposed to intercept HTTP-requests, alter form values and then try to pass the information t our system, expecting it to work.

Another thing that’s neat is to watch a co-worker try to mess with all kinds of SQL injection (both manually and automated) and not get anywhere. Hey, I’m not saying I’m the sharpest knife in the kitchen drawer, and I’m always looking for ways to improve what I’m doing — all I’m saying is that it’s nice when intentionally designed system security starts paying off.

 

Thursday, June 22, 2006

How interactive can you get for $1 million?

Would you like to become an Interaction Designer for up to $1,000,000.00/year?

I know for sure that for that amount of money, I could design a heck of an interaction. Check out the jop posting before it disappears.

Milliondollarjob

The company looking for an Interaction Designer is NextPage, a Utah-based company that has been fiddling around with document management for years. They re-thought their entire product line and future a few years ago and seem to know now what they want.

Several years ago, I used to work on some projects for NextPage as a consultant. They had a very nice and bright crew, and they were eager to get much accomplished. However, the management team basically reorganized and restructured the company and its product line, so it was difficult for some of those nice people to stay on. I think just about everyone I used to work with at NextPage has since jumped ship.

Still, $1 million per year is a nice chunk of change. Makes you think, doesn’t it?

Alternate job posting on NextPage’s web site, without the dollar figure.

 

Thursday, June 15, 2006

ASP 0138 Errors

You just made a little tweak to your ASP page, tinkered around with some JavaScript, modified a little bit of CSS, and now you’re ready to test the revised page.

KA-BOOM!

All of a sudden, you’re getting 0138 errors, indicating that somehow you’ve nested one <script…> tag inside another.

The problem is: You didn’t!

Even after reviewing the generated source code and analyzing every <script…> tag, you can’t see anything wrong with your code. A quick trip to Google confirms that only careless coders will get this error, or something to that effct. And yet, you’ve taken great pains to make sure that everything is correct. Plus, the only thing you’ve changed has already been changed on many other pages . . . successfully.

Now what?

As ridiculous as it may seem, one way to solve this problem is the following:

1. Find the inline JavaScript, you know, the line that looks similar to this <script type=”text/javascript” language=”JavaScript”>. “Inline” means that it shows up somewhere else in your code than in the <head> section.

2. Break it up. Classic ASP / VBScript gets “very nervous” when it encounters inline <script…> tags under certain conditions. Try something like this:

<%
Response.Write("<scr" & "ipt type=""text/javascr" & "ipt"">")
%>

It sounds and looks ridiculous, right? However, the errors most likely go away unless, of course, you’ve actually nested one <script…> tag inside another.

Additional resources:

Forum Discussion on DevX

SQL Server 200 & ASP

Milonic

Friday, June 09, 2006

IE7 CSS Hacks

Just in case you were wondering what’s going to change and how much retro-fitting you’ll have to do for your clients when the masses (?) start upgrading and switching to IE7, here’s a very well written and documented article that outlines IE CSS hacks.

As is common with any technical issue, there are evangelists and practicioners, there are Microsofties and OpenSourcerers and purists — and all camps are represented in the article’s accompanying comment section.

Still, if you need IE7–specific information, this article is a great read. Especially since one of my favorite CSS hacks might now no longer be supported in FireFox only:

/* FIREFOX */
html>body #addToMaster {height: 20px;}

As the author Nanobot points out:

If a simple selector is missing on either side of the child combinator (>), Internet Explorer 7 incorrectly assumes that the missing simple selector is a universal selector. So >body is treated by IE7 like *>body, while other browsers ignore it because it's a parsing error. Similarly, IE7 treats >> like *>*>*.

IE7 has the same quirk with other combinators. +p is treated like *+p and ~p is treated like *~p. (Note: The ~ combinator is an upcoming CSS 3 feature and is not valid CSS 2.1.)

>body {} selects the body element in IE 7 only. It may or may not work in future versions. Warning: this uses invalid CSS!