Future Media Standards & Guidelines

Server-Side Application Development Standards v1.08 (withdrawn)

1. Introduction

This standard is designed to ensure that all server-side application development maintains the integrity and security of www.bbc.co.uk. The standard doesn't cover applications on news.bbc.co.uk (although it's hoped that future versions might).

All other applications MUST follow these guidelines, and they will be applied to all applications, be they completely new or minor updates.

In matters of integrity and security, precedent is irrelevant.

This document assumes that you have read BBC Internet Environment - BBC servers, software, and filesystem [Internal BBC document internal BBC doc – gain access via your Technical Account Manager] available from the BBC support extranet.

Vital information External developers should gain access to BBC internal documentation via their assigned Technical Account Manager.

1.1 Application testing /submission procedures

Projects SHOULD be developed and made operational on an environment that is as close to the live serving infrastructure as is reasonably possible. Once presented for integration with the live environment, future patches to an application should be kept to a minimum. You must not submit an application to Internet Operations until it is a suitable release candidate. Applications that are known to require further functionality or have not been thoroughly tested, are not good release candidates!

Provided you comply with this document your code is likely to be accepted, except in exceptional circumstances where code is likely to cause problems with the integrity or security of bbc.co.uk. Any rejections will be accompanied with a reason.

You should assume that code will always be rejected if you fail to meet any MUST or MUST NOT items in this document. If it is not possible for you to meet them, you MUST talk to the Application Development Working Group at the earliest opportunity.

Suppliers should submit their code through their BBC Technical Account Manager. When presenting changes, you SHOULD only submit the files (scripts or modules) that have changed, but present the entire file, (rather than output from diff).

Top of page

2. Design and Planning

As early as possible in your project (before starting to code) you MUST consider the following issues.

2.1 You MUST confirm that the functionality does not already exist

You MUST confirm that the functionality does not already exist in an existing script or application, by checking on the following BBC script repositories:

Useful BBC perl modules are discussed in Appendix A of the BBC Internet Environment [Internal BBC document internal BBC doc - gain access via your Technical Account Manager] available on the extranet.

You should also check CPAN (Comprehensive Perl Archive Network), pug@lists.bbc.co.uk or ask on the Talker (see Siemens Internet Operations Request Forms [Internal BBC documentinternal BBC doc - gain access via your Technical Account Manager] for access details).

If the above fails, email the Application Development Working Group.

Code may be rejected if it duplicates or closely mirrors existing functionality without very good reason (e.g. if it is a high-performance functionality-lite version of an existing script) due to the additional on-going costs for maintenance and support, plus the increased risk to security. Ignorance is not a defence.

2.2 You SHOULD consider whether a client side (Flash or JavaScript) solution would be more appropriate

If so, you SHOULD read the BBC standards for Flash, JavaScript and Accessibility. You may also wish to check whether your functionality can be delivered using XSSI. There are some useful Apache modules that have been released on bbc.co.uk/opensource.

2.3 You MUST carefully consider which language and environment is appropriate to your application

You SHOULD use Perl or mod_perl, and it SHOULD be portable across both Solaris and Linux. mod_perl is preferred unless you can justify why it would be better as a CGI.

If you are not using Perl or mod_perl under Solaris or Linux, you SHOULD have a solid business case justifying your choice, and MUST seek approval from the New Media Technical Architect (cc the Application Development Working Group) BEFORE your begin any development.

This includes, but is not limited to:

  • C or C++, C#, Java
  • Any non Solaris or Linux based hosting environments
  • Perl based CGI

Non Perl based code SHOULD be portable across both Solaris and Linux, unless there are well documented performance or operational reasons why only one platform is supported.

For the purposes of this document, mod_perl refers to Apache registry scripts only , and CGI as a perl script which requires re-compilation each time it is invoked.

2.4 You MUST carefully consider when you SHOULD use flat files, DBMs or other filesystem devices, and when you SHOULD use a database

When making this decision you SHOULD:

You MUST agree the final decision with the BBC Technical Architect.

If a database solution is to be used, you MUST comply with the Database Standards and MUST ensure a BBC New Media DBA reviews your database design before you begin development.

2.5 Resource Planning

You SHOULD think carefully about patterns of usage for your application. Will there be particular a time when usage will be very high (for example, after a TV programme)? Is your application usage seasonal (for example, a revision aid)?

You SHOULD plan for peak usage. If your application overloads the infrastructure it may have to be disabled to ensure other services can continue.

  • If you expect a peak of more than 1000 requests per hour to your application, you MUST discuss the resourcing needs of your application with the Application Development Working Group.
  • Any application expecting over 50,000 requests per hour MUST seek advice from the New Media Infrastructure group early, and this MUST be prior to any development work starting to ensure adequate resources will be available.
  • An application will not be put live until adequate hardware resources are available to support it. You MUST plan early to ensure resources are available.

2.6 Cacheing Strategy

A common strategy for improving the scalability of popular applications is to use cacheing, see section 4, for more on Scalability. Here is a summary of the various approaches to cacheing that have been used on bbc.co.uk

  • On the application servers you could use a cacheing module, such as Cache::AgainstFile (documentation on technet [Internal BBC document internal BBC doc - gain access via your Technical Account Manager]) to reduce the incidence of file IO. You might also consider in-memory cacheing under mod_perl. If you need to cache a large data structure then consider a start-up script, but having first read section 6.10.
  • Alternatively, if your content is semi-dynamic, and particularly if you expect demand to be high, the use the content servers in combination with the page-flattener. The page-flatter will pre-process a users request.

For the most recent discussions on cacheing techniques, you can check Semi-dynamic Site Standards [Internal BBC document internal BBC doc - gain access via your Technical Account Manager]

2.7 Proprietary Software

Should a project require the installation of proprietary software then this must be raised with BBC New Media's Technical Design Architect before project resources are committed.

Top of page

3. Security

Your application MUST NOT do anything that may compromise the security of the server, data on the server, other applications, other hosts, or the network. See the Baseline Security Standards.

There is no automatic way to check the security of applications – an engineer has to read the script and check it line by line. To make checking as fast as possible you SHOULD write clear code that is obviously secure and SHOULD carry out any security checking as near to the point of usage as possible.

3.1 You SHOULD check your application with all warnings and checks enabled.

3.2 You SHOULD consider all data read by your application

You SHOULD consider all data read by your application whether from the user, the file system, or a database to be untrustworthy. Don't assume data you read in is in the correct format, is of the correct length, or is correctly delimited or terminated, or is even there.

  • Cross site scripting

    When accepting data from untrusted sources, such as user-generated content, you should be careful to validate this data as it may contain code which could then be executed at a later time (e.g. Javascript contained in a form submission).

  • Capturing Personal Information

    For applications that process personal data you MUST adhere to the requirements of the Technical Implementation of DPA.

  • Environment Variables

    You MUST NOT modify environment variables in your code. Also be aware that some variables, for example HTTP_REFERER are easily spoofed by user-agents.

3.3 Applications MUST be careful to ensure that all filesystem access is carried out safely

This applies to all filesystem operations, not just reading and writing, for example tying hashes, changing permissions, moving files, or creating directories.

An application MUST ensure:

  • Filesystem areas are used correctly, as outlined in the BBC Internet Environment document [Internal BBC document internal BBC doc - gain access via your Technical Account Manager].
  • File paths do not contain '..' or \0 (except to terminate a string). By using '..' and inserting a null character a user could gain access to any file on the filesystem.
  • File paths only contain alphanumerics and the following characters /-_@%. (forward slash, dash, underscore, at sign, percent, full stop).
  • Data written to the filesystem MUST be of a sensible size. Do not allow users to upload unlimited amounts of data.

3.4 Applications SHOULD only access data in the site from which it is called

For example, a quiz on the Arts site SHOULD only access data in '/home/system/data/arts' etc.

  • Exceptions to this rule MUST be cleared with Siemens Internet Operations, unless you are using the BBC::KW perl module.
  • See BBC::KW module [Internal BBC document internal BBC doc - gain access via your Technical Account Manager].

3.5 You SHOULD check any variables substituted into SQL statements

Databases present an opportunity for users to display unauthorised data or change information they shouldn't. You SHOULD use placeholders in your SQL statements.

3.6 Forking processes

You SHOULD NOT fork other processes, and under mod_perl you MUST NOT fork at all. Use built in methods, or standard modules instead of forking.

  • If you have to fork another process you MUST ensure the integrity of any data involved.

3.7 Connecting to other hosts

If you need to connect to another host you SHOULD treat it as carefully as a filesystem operation, and be aware of compromising the host you're connecting to, or holding connections open. You MUST contact the Application Development Working Group for advice.

You SHOULD implement a list of allowed hosts, and check against this prior to connecting, or hardwire the hostname into the code.

You SHOULD consider issues like denial of service (including ones that could be caused by your application), and how your application behaves when trying to connect to very slow, or dead hosts.

3.8 You SHOULD consider deadlock/DoS situations

You SHOULD consider deadlock/DoS situations, such as the following:

  • You have 40 apache children where your application (A) runs. You call another (B), which has only 5 apache children.
  • (B) quickly becomes swamped, which in turn locks up all the children on (A). As fast as one request is dealt with, another arrives.
  • Requests back up for (A), until eventually no more requests can be handled.

If you encounter Denial of Service attacks, you SHOULD consider the following:

  • The application provider SHOULD agree with Siemens Internet Operations a mechanism to block abuse of the application.
  • You MUST inform the Application Development Working Group of any aspect of your application that may be subject to DoS attacks.

3.9 Evaluating code at run-time

You MUST NOT evaluate code at run-time, unless there is a very clear need to do so, and there is no alternative.

  • Note that in perl eval( EXPR ); is not the same as eval{ BLOCK };

3.10 Code with known memory leaks will be rejected

Code that is discovered to have memory leaks may be removed by Siemens Internet Operations.

  • If you are using C or C++ you SHOULD take extra care. You SHOULD always check data is not too long for a buffer, and MUST not use unallocated, or freed memory.

3.11 Email

If you application needs to send email, then you MUST contact the Application Development Working Group for advice.

3.12 Sending system information to the user

You MUST NOT send system information, such as paths, to the user as this information is useful in trying to break the security of the server. Such information SHOULD be sent to an error log instead (STDERR goes to the error log for CGIs). There is more information on using error logs in section 5.3.

Top of page

4. Scalability

4.1 Likely usage and usage patterns

You SHOULD think carefully about patterns of usage for your application – see section 2.5.

4.2 Reusing existing applications

If you are planning to reuse an existing application, you should consider the scalability of that application.

4.3 Load balancing

An application SHOULD be capable of being load balanced across multiple servers. Typically this means any stateful application SHOULD use a database storage solution.

  • Any special considerations for doing this MUST be well documented, and easily available.

4.4 Reducing file IO

Reducing file IO is often a good way to make your application scale further. If you parse a file repeatedly you SHOULD consider caching the parsed data, for example with the Storable module in Perl. If using mod_perl, it may be possible to cache heavily used information or templates in memory (but be aware of excessive memory usage causing swapping).

4.5 Locking and deadlocks

If you are using any form of locking, you SHOULD take care to avoid deadlocks. You may want to ensure your code has a mechanism to deal with deadlocks if they occur.

4.6 Performance of libraries

You SHOULD consider the performance implications of any libraries you use. For example, the use of an XML parser to read a config script.

You SHOULD always re-use an existing module or library if possible.

4.7 Includes

You SHOULD carefully consider where dynamic applications are linked from and included on pages. You SHOULD consider the use of dynamically generated XSSI includes where appropriate.

Top of page

5. Maintainability

5.1 Documentation

Each file (scripts, modules, configuration files, etc) MUST include:

  • A clearly specified author or maintainer.
  • A brief description of the file's purpose.
  • The application, module or suite to which it belongs.
  • A version number, which MUST increment with every new live release. In a perl/mod_perl script this MUST be set in $VERSION. The recommended way to do this is via CVS revisions.

If this information is not present, Siemens Internet Operations will automatically reject your application.

5.2 Code layout

While you can choose your own rules about bracing style, tab width, spaces and so forth, for new files, you MUST be consistent in applying the style to your code. When modifying existing code that has a well-ordered layout, you MUST use the same standard in your modification. You MAY wish to use the Perl Coding Guidelines and C++ Coding Guidelines.

5.3 Error Messages

You SHOULD always give a clear, precise error message, which will allow the problem to be tracked down quickly.

Good error messages SHOULD:

  • go to STDERR;
  • include the programme that caused the problem;
  • list the failed system call and arguments;
  • contain the standard system error message for what went wrong (very important)

For example: open (FH, "< $path") or die "Couldn't open file.\n"; does not specify what you couldn't open, what was it for, and why it failed. The following example fixes this, and omitting the newline character "\n", ensures that the script name and line number will appear in the error log.

open (FH, "< $path") or die 
"Couldn't open cache file '$path' for '$quiz' - $!";

It's a good idea to be able to disable debugging output from a single control point, e.g $DEBUG=0;.

Applications should only write to the error log when a critical error has occurred, and the message should report on program functionality. Some information such as passwords, or anything that could uniquely identify an individual, should not be written.

Under normal operations, scripts SHOULD be silent.

5.4 Creation of directories

Your application SHOULD create any directories it requires automatically, you MUST NOT depend on Siemens Internet Operations creating directories (other than top level ones) for you. In perl you can use File::Path to create a series of directories. Again, you SHOULD ensure meaningful error messages are given (such as the full path the application was looking for).

5.5 Clean-up

Applications that write any data to disk, especially for caching, MUST ensure they clean up after themselves. If a separate cleaning script/cron is used, it MUST be checked and installed before the main application is used.

  • When using caches, you may want to implement a way to clear or disable the cache that you can control (via a config file).

5.6 Provision of automated monitoring

You SHOULD ensure a suitable level of automated monitoring is in place for your application.

This may involve you writing suitable monitoring code and submitting it as part of your application release. You should monitor the system resources used and the availability of your application. You are advised to monitor mod_perl applicatons by going through www.bbc.co.uk.

  • Siemens Internet Operations may run this, or it may be best done by yourself, or BBC Broadcast (Siemens Internet Operations can provide advice if you require it).
  • IF&L's gigaquiz monitoring [Internal BBC document internal BBC doc - gain access via your Technical Account Manager] is a good example of remote monitoring.
  • There are already available a number of various systems, such as Nagios and BBC Search also has a good example of automated monitoring, run by BBC Broadcast. Please contact BBC's Technical Architect to find out more.

5.7 Embedding presentational elements / markup in code

You SHOULD NOT put HTML, XML markup or any other presentation elements within your code. You SHOULD use a suitable templating module (such as BBC::CGI::Template2 or IFL::CGITemplate) instead – check with your BBC Technical Account Manager for advice on suitable modules.

If you do include presentation elements, you MUST separate them into another file, module or a clearly marked section of your code.

For reasons of cost, web content is not replicated to the cgi-perl hardware. In general applications don't need access to files stored within the /www directories, so this isn't usually a problem. However, there are some exceptions that will be allowed, but you SHOULD have at least considered:

  • that Apache 2 is capable of post-processing SSI statements
  • using the /data or /perldata areas

5.8 Use of /data area for configuration purposes.

To avoid unecessary code changes, configuration information SHOULD be stored in the data folder. Configuration files in this location can then be easily altered by trusted users (those with access to ftp.bbc.co.uk).

The nature of the configuration should be to manage behaviour between the application and the user. Applications that use configuration files to change their interaction with the underlying system will be seen as a security risk and rejected at test time. Usernames and passwords MUST NOT be used in a configuration file. Information of this type should be stored in a Configuration module. Any file paths in configuration files must go through the BBC::KW module, or equivalent. URLs and hostnames from configuration files should be bound by a regular expression.

Top of page

6. Language Specifics – Perl (and mod_perl unless noted)

The following sections give advice on developing in Perl and mod_perl. Other languages are currently not included, but may be added at a later date. In all cases, the generic guidelines above take precedence.

6.1 Use of warning, strict and taint pragmas

  • When developing code you MUST run perl scripts under the -w flag at all times. You may, however, explicitly turn it off for particular portions of code by using the use warnings pragma or the $^W variable (if necessary) within the script. If this produces pages of warnings, you MUST fix the underlying problems before releasing your code. The -w flag may be removed prior to submission for installation.
  • Perl code MUST compile with use strict and you SHOULD always run scripts with strict enabled, or know the reason why you are not.
  • Also during development, you SHOULD use taint checking -T flag, an exception here is that taint does not work under mod_perl. The PerlTaint apache directive MAY be considered, please check with Siemens Internet Operations that its use would be suitable.

The use sigtrap and even use diagnostics pragmas may also prove useful.

6.2 You MUST use Perl version 5.6.1

You MUST check with Siemens Internet Operations which version of Perl is current on the live servers, then test your code with this, but do not rely on versions not changing.

You MUST test scripts under Perl 5.6.1. You MAY also want to test them under 5.8.

You SHOULD pay careful attention to platform, or language specific modules. Storable and DBM can be problematic.

6.3 Variable and function names

We use the case of variable names to show their scope:

  • Constants MUST be written in ALL_CAPS with underscores to separate words, and without a preceding $.
  • Global/package scoped variables MUST begin with an upper-case letter, and use either underscores or studly caps (BiCapitalisation) to separate words (for example, $CustomerDBUser or $Customer_db_user are permitted).
  • Locally scoped variables – my() or local() variables – MUST begin with a lower case letter, and use either underscores or studly caps to separate words (for example, $indexFileName or $index_file_name are permitted).
  • Private functions or methods SHOULD begin with an underscore.

6.4 You MUST use /usr/local/perl/bin/perl

You MUST use /usr/local/perl/bin/perl unless told otherwise by Siemens Internet Operations or the Application Development Working Group.

6.5 Use of ‘use'

You SHOULD use 'use' or 'require', and MUST NOT use 'do EXPR' ('do {BLOCK}' is OK).

  • You SHOULD NOT add extra paths to @INC that are already present in the system library path (e.g. '/home/system/cgi-bin/lib').
  • Generic modules SHOULD be placed in a suitable location under /home/system/cgi-bin/lib.

6.6 PackageSet (not mod_perl)

Unless you are using mod_perl, you SHOULD always use PackageSet [Internal BBC document internal BBC doc - gain access via your Technical Account Manager].

6.7 You SHOULD prefer built-in commands to using system() or forking another process

For example, in Perl, use the built-in rename rather than forking 'mv'.

6.8 Email

You SHOULD use BBC::SendEmail unless you have good reason not to.

You SHOULD NOT call sendmail directly.

6.9 Use of ‘eval'

You MUST NOT use 'eval $scalar' or the '/ee' regex modifier.

  • Use of 'eval { ... block ... }; if ($@) { ... block ... }' is encouraged.

6.10 Mod_perl

If you are writing mod_perl applications, you MUST read the Mod_Perl guidelines [Internal BBC document internal BBC doc - gain access via your Technical Account Manager].

  • mod_perl applications SHOULD be implemented as Apache::Registry scripts.
  • Your application MUST NOT require custom configuration of either Apache's configuration (httpd.conf), or require any startup scripts unless you have cleared this before starting development with the Application Development Working Group.
  • Note: that the Apache::Registry modules are not installed on live.

6.11 Modules

The re-use of CPAN modules is generally encouraged, particularly for performing core functions. You are advised that many common modules, such as those distributed with Linux distributions, are not on bbc.co.uk. You MUST use CGI.pm module when capturing input parameters. You SHOULD NOT use BBCparse.pm which has been deprecated (since version 1.06 of this document).

6.12 Check module (version) availability

Before commencing development you SHOULD check what modules are available, and that the version installed has the features you need. It is not uncommon for the versions of modules on live servers to be a year or two old.

6.13 Accessing the filesystem

When accessing the filesystem, you MUST use one of the following:

  • BBC::KW; [Internal BBC document internal BBC doc - gain access via your Technical Account Manager] - this is the preferred solution.
  • File::Policy and File::Slurp::WithinPolicy - this is an easy to use secure file I/O module and uses BBC::KW internally. These modules are particularly recommended for anyone considering a release to CPAN.
  • Check the path yourself, with code similar to:
    use CGI;
    my $query = new CGI;
    my $path = $query->param('path');
    my $data_file = '/home/system/data/'.$path.'quiz.dat';
    die "Unsafe path '$datFile'." 
    unless $path =~ /^history\//;
    # Hardcoded site check
    die "Unsafe path '$datFile'." if $datFile =~ /\.\./;.
    die "Unsafe path '$datFile'." 
    unless $datFile =~ /^[\w\/.%@-]+$/);
    # \w includes underscore
    open (FH, "< $datfile");
    You SHOULD call the checking code directly before the path is used.
  • You MUST NOT return file paths in error messages to users. You SHOULD include paths in error messages to STDERR, or log files.
  • You SHOULD NOT read or write data outside your application's space.
    • Exceptions to this rule MUST be cleared with Siemens Internet Operations, unless you are using the BBC::KW perl module.
    • See BBC::KW module [Internal BBC document internal BBC doc - gain access via your Technical Account Manager].
  • As a last resort, hardcoded paths MAY be used either directly in the script or as a constant.
  • You MAY want to avoid this, as any changes to the path require the script to be re-checked by Siemens Internet Operations, which can take time.

Top of page

7. Triggers for updating this document

Any of the following SHOULD be considered a trigger for updating this document

  • Major revision to operating systems, or perl versions
  • Major infrastructure changes
  • Changes in supporting documents, most notably security policy.

In any case, it SHOULD be fully reviewed at least once every 6 months.

Top of page

8. Document history

12/06/2006 v1.08 Revised section 3.2 in line with Technical Forum agreement (26/04/06) to reference Technical Implementation of DPA requirements. Tred Magill
11/06/2006 v1.07 Update following working group meeting on 14/03/2006
  • Removed requirement to use CVS, and insisted on code submission via Tech. Account Man.
  • Added link to new extdev documentation area.
  • New section on using cacheing to cope with high load
  • Distinquished between Sensitive Personal Information and Personal Information (pending more input from DPA expertise)
  • Added note that Apache::Registry module is not available on bbc.co.uk
Gavin Johnson
16/11/2005 v1.06 Updates following working group meeting on 11/10/05 Gavin Johnson
20/09/2005 v1.05 Update following working group meeting on 9/8/05 Gavin Johnson
16/03/2005 v1.04 Final edits required for approval from Tech Forum on 14/03/05 (incl. from Matt Blakemore) Jonathan Hassell
10/03/2005 v1.03 Final inserts of URLs for Script WIKI etc. Jonathan Hassell
08/03/2005 v1.02 After corrections at App Dev WG meeting on 8/3/05 (all updates from v1.00 now in yellow for easy review) Jonathan Hassell
20/1/2005 v1.01a Updates inserted into standard, from WG meeting on 11/1/05 Jonathan Hassell
02/03/2005 v1.01 Added MUSTs from Perl Coding standards Sally Underwood
21/04/2004 v1.00 Standard renumbered as 1.00 on approval by Standards Exec Jonathan Hassell
08/04/2004 v0.23 Minor alterations of line-breaks in examples Jonathan Hassell
07/04/2004 v0.22 Email addresses changed to be accessible externally; link added to request access to the Talker; updated URLs for environment doc to non-draft address; tweak of grammar in 5.1; removal of should/must contradiction in 2.1; reformatting of comments in 5.2; capitalisations in 5.5 Jonathan Hassell (on behalf of Damion Yates & Will Green)
06/04/2004 v0.21 Including amendments required by Tech Forum to pass document (see minutes of Tech Forum 24/3/04 ) Jonathan Hassell
19/03/2004 v0.207 Converted WIKI into Word format, renumbered as v0.207 Jonathan Hassell
16/03/2004 v2.0.7 (WIKI) Restructure of document; and integration of comments from Damion Yates, Declan White, John Alden , Mark Hewis Murray Walker, Gavin Johnson, Jonathan Hassell
16/03/2004 v2.0.6 (WIKI) Pre-restructure Murray Walker, Gavin Johnson, Jonathan Hassell
10/03/2004 v2.0.5 (WIKI) Edits prompted by points in minutes of App Dev WG on 9/3/04 Murray Walker
13/02/2004 v2.0.4 (WIKI) Edits prompted by points in minutes of App Dev WG on 10/2/04 and Tech Forum on 27/2/04 (splitting the original doc into Standards & Guidelines) Murray Walker
x/08/2003 V2.0.3b draft (WIKI) Original document by Will Green (Siemens Internet Operations) Will Green

Document editor: Editor, Standards & Guidelines. If you have any comments, questions or requests relating to this document, please contact the Editor, Standards & Guidelines.

Like all other Future Media Standards & Guidelines, this page is updated on a regular basis, through the process described on About Standards & Guidelines.

Top of page

BBC navigation

BBC © 2014 The BBC is not responsible for the content of external sites. Read more.

This page is best viewed in an up-to-date web browser with style sheets (CSS) enabled. While you will be able to view the content of this page in your current browser, you will not be able to get the full visual experience. Please consider upgrading your browser software or enabling style sheets (CSS) if you are able to do so.